Skip to content
This documentation is currently in preview, therefore subject to change.

HTML Template Syntax

HTML templates use a simple templating language and data sources to generate HTML or other text formats. HTML templates look like regular text with embedded template expressions.

The example below shows how a data source may appear using the provided template:

<div>
<p>Name: {{Name}} {{Surname}}</p>
<p>Address: {{Address.Number}}, {{Address.Street}}, {{Address.City}}</p>
</div>

An expression consists of {{, some contents, then }}. When the template is executed, these expressions are replaced with values from an input object.

Language Features

Simple Expressions

The following template defines two template expressions. If applied to the input object, the expressions will be replaced by the corresponding properties. The result is then:

<p>{{firstname}} {{lastname}}</p>

Nested Input Objects

Sometimes, the input object contains other objects or arrays. In such a case, you can use a dot-notation to gain access to the nested properties. For example:

{{Person.FirstName}} {{Person.LastName}}

Some built-in helpers allow you to change the current context to a nested object. You can then access this object as if it were the root object.

Evaluation context

When working with templates, the “context” refers to the current scope of data available for evaluation.

The this keyword can be used to access the current context.

The current evaluation context can be changed through the use of different helpers, such as the with helper.

The with helper dives into an object, giving you access to its properties:

{{#with person}}
{{firstname}} {{lastname}}
{{/with}}

You can optionally provide an {{else}} section which will display only when the passed value is empty.

{{#with city}}
{{city.name}} (not shown because there is no city)
{{else}}
No city found
{{/with}}

HTML Escaping

Because it was originally designed to generate HTML, templates escape values returned by a {{expression}}. If you don’t want to escape a value, use the “triple-stash”, {{{.

raw: {{{specialChars}}}
html-escaped: {{specialChars}}

Raw Block:

Raw Blocks are used to completely skip any template parsing for the content inside it. Anything wrapped within the {{{{raw}}}}...{{{{/raw}}}} is produced in the output verbatim, exactly as written.

{{{{raw}}}}
{{#each items}}
<p>{{this}}</p>
{{/each}}
{{{{/raw}}}}

Conditionals

You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], the block will not be rendered.

<div>
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>

If the input is an empty JSON object {}, then author will become undefined and if condition fails, resulting in the output below:

<div></div>

When using a block expression, you can specify a template section to run if the expression returns a falsy value. The section, marked by else is called an “else section”.

<div>
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{else}}
<h1>Unknown Author</h1>
{{/if}}
</div>

You can use the unless helper as the inverse of the if helper. Its block will be rendered if the expression returns a falsy value.

<div>
{{#unless license}}
<h3 class="warning">WARNING: This entry does not have a license!</h3>
{{/unless}}
</div>

If looking up license under the current context returns a falsy value, the warning will be rendered. Otherwise, it will render nothing.

Loops

You can iterate over a list using the built-in each helper. Inside the block, you can use this to reference the element being iterated over.

<ul class="people_list">
{{#each people}}
<li>{{this}}</li>
{{/each}}
</ul>

You can use the this expression in any context to reference the current context.

You can optionally provide an else section which will display only when the list is empty.

{{#times}}
{{#person}}
<p>Meeting with {{person}} at {{time}}.</p>
{{else}}
<p class="empty">No meeting at {{time}}.</p>
{{/person}}
{{/times}}

When looping through items in each, you can optionally reference the current loop index via {{@index}}.

{{#each array}} {{@index}}: {{this}} {{/each}}

Additionally for object iteration, {{@key}} references the current key name:

{{#each object}} {{@key}}: {{this}} {{/each}}

It’s often useful to know when you’re on the first or last item in a loop. The first and last steps of iteration are noted via the @first and @last variables when iterating over an array. When iterating over an object only the @first is available. Nested each blocks may access the iteration variables via depth based paths.

<ul>
{{#each items}}
<li>
{{this}}
{{#if @first}}<strong>(first)</strong>{{/if}}
{{#if @last}}<strong>(last)</strong>{{/if}}
</li>
{{/each}}
</ul>

When in a loop, the parent index can be accessed with {{@../index}}.

{{#each teams as |team|}}
<h3>{{team.name}}</h3>
<ul>
{{#each team.players}}
<li>{{this}} plays for {{team.name}} (Team index {{@../index}})</li>
{{/each}}
</ul>
{{/each}}

Similarly, the @root keyword will access the top-level context:

{{#each departments}}
<h4>Department: {{name}}</h4>
<p>Company: {{@root.companyName}}</p>
<ul>
{{#each employees}}
<li>{{this}} works at {{@root.companyName}}</li>
{{/each}}
</ul>
{{/each}}

Lookup

The lookup helper allows for dynamic parameter resolution. It is useful for resolving values for array indexes.

It can also be used to lookup object properties based on data from the input.

{{#each people}}
{{.}} lives in {{lookup ../cities @index}}
{{/each}}

It can also be used to retrieve object properties using input data. In the following, a more advanced example demonstrates how a lookup within a sub-expression can shift the evaluation context to a different object, guided by a specific property-value:

{{#each persons as |person|}}
{{person.name}} lives in
{{#with (lookup ../cities person.resides-in) as |city|}}
{{city.name}} ({{city.country}})
{{/with}}
{{/each}}

Formatting Values

Dates and Times

Dates from a data source property can be formatted using the formatdate function.

{{formatdate createddate 'dd/MM/yyyy HH:mm:ss'}}

Or to return the relative time use the friendly formatting option:

{{formatdate createddate 'friendly'}}

The following table shows the keys and sample outputs used by the friendly format:

RangeKeySample Output
0 to 44 secondssin seconds
45 to 89 secondsmin a minute
90 seconds to 44 minutesmmin 2 minutes … in 44 minutes
45 to 89 minuteshin an hour
90 minutes to 21 hourshhin 2 hours … in 21 hours
22 to 35 hoursdin a day
36 hours to 25 daysddin 2 days … in 25 days
26 to 45 daysMin a month
45 to 319 daysMMin 2 months … in 10 months
320 to 547 days (1.5 years)yin a year
548 days+yyin 2 years … in 20 years

Whitespace Control

Template whitespace may be omitted from either side of any expression statement by adding a ~ character by the braces. When applied all whitespace on that side will be removed up to the first expression or non-whitespace character on that side.

<nav aria-label="Main menu">
{{#each menu~}}
<a href="{{url}}" class="menu-link" aria-current="{{#if current}}page{{/if}}">
{{~title}}
</a>
{{~/each}}
</nav>