12 KiB
EJS Syntax Reference
EJS is designed to be flexible and easy-to-write, but without too much abstractions to cover up the HTML base.
Table of contents
- Basic format
- Delimiters
- Starting tags
<%=: Escaped output<%-: Unescaped output<%#: Comments<%: Scriptlet<%_: Scriptlet, removes all preceeding whitespace
- Ending tags
%>: Regular ending tag-%>: Removes trailing newline_%>: Removes all trailing whitespace
- Literal tags
- Including other files
- “Preprocessor” directive
- JavaScript
include()function
- Copyright
Basic format
An EJS “tag” is the primary functioning unit in an EJS template. With the exception of the literal tags, all tags are formed by the following format:
<starting content closing>
The spaces between starting and content, and content and closing are not required; they are recommended though for readability.
Delimiters
The starting and closing tags contain a special string called the
delimiter. In this document, all tags are shown using the % delimiter, which
is the default. You can, however, change that to your liking. See
https://github.com/mde/ejs#custom-delimiters for more information on how to
change it.
Starting tags
<%=: Escaped output
The most important thing for a template language is the ability to pass
variables to the template. In EJS, this is done with the <%= and <%- tags.
<%= is the starting tag to use for variables that need to be escaped. If the
specified string contains forbidden characters like < and &, they are
escaped automatically with HTML codes.
The content of the tag can be any valid JavaScript operators, so tags like
<%= name ? name : (lastName || 'John Doe') %> would work as intended.
Example
EJS
<p>Hello, <%= name %>.</p>
<p>Hello, <%= 'the Most Honorable ' + name %>.</p>
Locals
{
"name": "Timoth<y>"
}
HTML
<p>Hello, Timoth<y>.</p>
<p>Hello, the Most Honorable Timoth<y>.</p>
<%-: Unescaped output
If your local contains preformatted HTML, you might not want to escape it. In
this case, use the <%- tag.
However, always be 100% sure the rendered local is sanitized, to prevent cross-site scripting (XSS) attacks.
Example
EJS
<p>Hello, <%- myHtml %>.</p>
<p>Hello, <%= myHtml %>.</p>
<p>Hello, <%- myMaliciousHtml %>.</p>
<p>Hello, <%= myMaliciousHtml %>.</p>
Locals
{
"myHtml": "<strong>Timothy</strong>"
, "myMaliciousHtml": "</p><script>document.write()</script><p>"
}
HTML
<p>Hello, <strong>Timothy</strong>.</p>
<p>Hello, <strong>Timothy</strong>.</p>
<p>Hello, </p><script>document.write()</script><p>.</p>
<p>Hello, </p><script>document.write()</script><p>.</p>
<%#: Comments
The <%# starting tag denotes that the statement is a comment that is not to
be executed or rendered in the resulting HTML.
Whitespace
The use of <%# might cause some useless whitespace, as illustrated by the
example below. You can trim it using the -%> ending tag.
Example
EJS
<div>
<%# comment %>
</div>
<div>
<%# comment -%>
</div>
HTML
<div>
</div>
<div>
</div>
<%: Scriptlets
Scriptlets in the <% tag allows logic to be embedded in an EJS template. You
are free to use any JavaScript syntax in this tag, and to mix JavaScript
with EJS. You can also put multiple statements in one tag.
Comments
All types of JavaScript comments are allowed, although it is preferable to use
the <%# tag for comments. For example, the following three code blocks are
equivalent, though <%# is the shortest.
<%# comment %>
<%/* comment */%>
<%// comment %>
Curly brackets
Always use brackets in loops and conditionals that involves mixing EJS template and JavaScript scriptlets. Omitting brackets might work for some statements, but the behavior is undefined and subject to change.
It is not necessary to use curly brackets for scriptlet-only code.
<%# Bad practice %>
<% if (true) %>
<p>Yay it's true!</p>
<%# Good practice %>
<% if (true) { %>
<p>Yay it's true!</p>
<% } %>
<%# These are all valid statements %>
<% var output
, exclamation = ''
, shouldOutput = false
if (true)
output = 'true!'
if (true) {
exclamation = 'Yay! ';
}
if (true) shouldOutput = true; %>
<% if (shouldOutput) { %>
<%= exclamation + 'It\'s ' + output %>
<% } %>
Line breaks inside a tag
Line breaks are allowed in <% tags.
Unless the statement involves mixing EJS and JavaScript scriptlet, always put complete statements in a tag. For example, the following works:
<% var stringToShow = thisIsABooleanVariableWithAVeryLongName
? 'OK'
: 'not OK' %>
While the following does not:
<% var stringToShow = thisIsABooleanVariableWithAVeryLongName %>
<% ? 'OK' %>
<% : 'not OK' %>
Semicolons
As is in JavaScript, semicolons are not required if proper line breaks are preserved.
Whitespace
The use of scriptlets might cause some useless whitespace, as illustrated by the example below. You can trim it by
- using the
-%>ending tag, and - using the
<%_starting tag or starting the tag in the beginning of a line.
Example
In the following example, several different coding styles are used simultaneously, to show that EJS is flexible with regards to personal habits. It does not mean that we recommend mixing coding styles in your own project.
EJS
<dl>
<%for (var i = 0; i < users.length; i++) { %><%
var user = users[i]
, name = user.name // the name of the user
%><%# comment %>
<%var age = user.age; /* the age of the user */%>
<dt><%= name %></dt>
<dd><%= age %></dd>
<%}-%>
</dl>
Locals
{
"users": [
{
"name": "Timothy"
, "age": 15
}
, {
"name": "Juan"
, "age": 51
}
]
}
HTML
<dl>
<dt>Timothy</dt>
<dd>15</dd>
<dt>Juan</dt>
<dd>51</dd>
</dl>
<%_ "Whitespace Slurping" Scriptlet
This tag is the same as a Scriptlet, except that it removes all whitespace before it.
Example
EJS
<ul>
<% users.forEach(function(user, i, arr){ -%>
<li><%= user %></li>
<% }); -%>
</ul>
<ul>
<%_ users.forEach(function(user, i, arr){ -%>
<li><%= user %></li>
<%_ }); -%>
</ul>
HTML
<ul>
<li>Anne</li>
<li>Bob</li>
</ul>
<ul>
<li>Anne</li>
<li>Bob</li>
</ul>
Ending tags
There are three flavors of ending tags: the regular one, the newline-trimming one, and the whitespace-slurping one.
%>: Regular ending tag
As used in all of the examples above, %> is the standard tag used to end an
EJS expression.
-%>: Newline-trimming ending tag
-%> trims all extra newlines a scriptlet or a comment might cause. It does
not have any effect on output tags.
Example
EJS
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' %>
End of template
---
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' -%>
End of template
Output
Beginning of template
End of template
---
Beginning of template
End of template
_%>: Whitespace-slurping ending tag
_%> removes all whitespace after it.
Literal tags
To output literal <% or %>, use <%% or %%>, respectively. If a customized delimiter is used, use
the same syntax. E.g. use <$$ to get <$ if the delimiter is $.
In regards to all the other tags, the literal tags are special as they do not need a closing tag to function.
However, think twice before you use these tags because < and > characters might
need to be escaped as < and >, respectively.
Example
The following example wrap <% and %> in a <pre>, where it is not necessary to
escape < or > at all.
EJS
<pre>This is literal: <%%</pre>
<pre>This is literal too: <%% %></pre>
<pre>This is literal as well: %%></pre>
HTML
<pre>This is literal: <%</pre>
<pre>This is literal too: <% %></pre>
<pre>This is literal as well: %></pre>
Including other files
EJS offer two ways of including other files. You can even include files that are not EJS templates, as the case is for CSS stylesheets.
For both flavors, if the file specified does not have an extension, .ejs is
automatically appended. If it is an absolute path, that file is included.
Otherwise, the file is assumed to be in the same directory as the parent
template.
The behavior of resolving included file path can be overridden using the
ejs.resolveInclude function.
“Preprocessor” directive
As a compatibility layer with EJS version 1, it is possible to use the
include directive in an unescaped output tag to directly “yank” the
text from another file, just like including a C header. However, as it is done
as a simple inclusion, you cannot pass arguments to the included template. You
can however make variables available in the parent template, that will be
visible to the child template as well.
This flavor of include is static, which means that the resulting
function contains the copy of the included file as when it was compiled, so
if you changed the file after compilation, the changes are not reflected.
Whitespace control
You most probably should not use the -%> ending tag on an include
directive, as it trims the whitespace after the included file.
Example
included.ejs
<li><%= pet.name %></li>
main.ejs
<ul>
<% pets.forEach(function (pet) { -%>
<% include included %>
<% }) -%>
</ul>
Locals
{
"pets": [
{
"name": "Hazel"
}
, {
"name": "Crystal"
}
, {
"name": "Catcher"
}
]
}
“Preprocessor" output
<ul>
<% pets.forEach(function (pet) { -%>
<li><%= pet.name %></li>
<% }) -%>
</ul>
HTML
<ul>
<li>Hazel</li>
<li>Crystal</li>
<li>Catcher</li>
</ul>
JavaScript include() function
With the release of EJS version 2, we have added a new way of including files
that is more intuitive. The include() function is available to the
templates, with the following signature:
include(filename, [locals])
One major difference with the method described above is that the variables in
the parent function are not visible to the child template, unless it is
explicitly declared in the locals object, or is passed as a local to the
parent template.
Also, the included file is compiled upon execution of the script, which means performance might be theoretically lower than the “preprocessor” flavor. In practice however, caching can make this difference negligible.
Some cautions MUST to be taken if the included filename is fetched from a
user during rendering time, as one could easily use private files as the file
name, like /etc/passwd or ../api-keys.
Example
This has the exact same effect as the example for the include directive.
included.ejs
<li><%= pet.name %></li>
main.ejs
<ul>
<% pets.forEach(function (pet) { -%>
<%- include('included', {
pet: pet
}) %>
<% }) -%>
</ul>
Locals
{
"pets": [
{
"name": "Hazel"
}
, {
"name": "Crystal"
}
, {
"name": "Catcher"
}
]
}
HTML
<ul>
<li>Hazel</li>
<li>Crystal</li>
<li>Catcher</li>
</ul>
Copyright
This document is under the following license:
Copyright © 2015 Tiancheng “Timothy” Gu
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.