HTML Template Engine

Variable Reference

HTML Template Engine supports a wide range of variables provided by your data context. You can insert these variables into your HTML using expressions like {{variable}}. Below are some common usage patterns:

Plain Variables

Simply reference a variable by its name to output its value. For example, if you write:

<p>{{variable}}</p>

the template will insert the value of variable where it appears.

Nested Variables

If your data contains nested objects, access sub-properties using dot notation. For instance, if your context includes an object called address with properties such as street and city, you can use:

<p>
  Street: {{address.street}}
</p>
<p>
  City: {{address.city}}
</p>

This instructs the engine to look up the address object first, then retrieve the specified field.

Arrays and Iteration

When a variable contains an array, you can iterate over its elements using the each helper. For example, if you have an array named array_variable, you might write:

<p>
  <ul>
  {{#each arrayVariable}}
    <li>
      {{@index}}: {{this}}
    </li>
  {{/each}}
  </ul>
</p>

In this snippet, {{@index}} provides the current iteration's index (starting at 0), and {{this}} refers to the current array element. If the array elements are objects, you can access their properties directly:

<p>
  <ul>
  {{#each arrayVariable}}
    <li>
      {{id}} - {{description}}
    </li>
  {{/each}}
  </ul>
</p>

Parent Context Access

When using block helpers like each or with, the current context changes. To reference a variable from an outer (parent) context, use the ../ notation. For example:

<p>
	<p>Outer: {{variable}}</p>
</p>
<p>
  <p>
    {{#each items}}
      <p>Inner: {{this}}</p>
      <p>Parent variable: {{../variable}}</p>
    {{/each}}
  </p>
</p>

Here, {{../variable}} accesses the variable from the parent context, even though the block's context is set to each element in items.

Using these patterns, you can effectively insert and manipulate data within your templates—whether dealing with plain values, nested objects, or arrays—allowing you to dynamically display content based on your data context.

Built-in Helpers

HTML Template Engine supports these built-in helpers. Below is an overview of each relevant helper and examples of how to use them in your template:

if Helper (Conditional Sections)

The if helper conditionally renders a block of HTML based on whether a given expression is truthy or falsy. If the expression is truthy, the content inside the if block is displayed; if it’s falsy, the block is skipped​. Template Engine considers the following as falsy values: false, null, undefined, the empty string "", the number 0, and an empty array []​. All other values are treated as truthy (including non-empty strings, non-zero numbers, objects, etc.).You can also specify an optional {{else}} section for the case when the condition is falsy. For example:

{{#if borrower_first_name}}
  <p>Hello, {{borrower_first_name}} {{borrower_last_name}}!</p>
{{else}}
  <p>Hello, valued customer!</p>
{{/if}}

In this example, if borrower_first_name has a value (truthy), it will render a personalized greeting with the borrower’s name. If borrower_first_name is not provided or empty (falsy), it will fall back to the "Hello, valued customer!"message. Using if in this way allows your template to handle optional data gracefully.

unless Helper (Inverse Conditional)

The unless helper is the inverse of if​. It will render the block inside it only if the given expression is falsy. In other words, {{#unless condition}} ... {{/unless}} is equivalent to saying “if NOT condition, show this block.” For example, if we want to show a warning when a borrower’s last name is not provided, we could use unless:

{{#unless borrower_last_name}}
  <p class="warning">Warning: No last name provided for the borrower.</p>
{{/unless}}

This will output the warning paragraph only if borrower_last_name is missing or falsy. If borrower_last_name has a value, the block is skipped (and nothing is output, since we did not provide an else for this case). The unless helper is handy for handling the “false” or empty scenario in your data without needing to explicitly negate an if. (If you do need an else with unless, consider using if/else for clarity.)

each Helper (Looping over Lists or Objects)

Use the each helper to iterate over an array or object and repeat a block for every element. When iterating over an array, the context inside the block becomes each element of the array in turn​. When iterating over an object’s properties, the context becomes each value, and you can also access the property name (explained below). Inside an each block, you can reference the current item with {{this}} or by its properties. For example, if borrower_table is an array of objects, you might do:

{{#each borrower_table}}
  <p>Item {{@index}}: {{name}} (ID: {{id}})</p>
{{/each}}
  • In this snippet, {{#each borrower_table}} will loop over each object in the borrower_table array. Inside the loop: {{name}} and {{id}} refer to properties of the current item (assuming each object has those fields). You can use any field that the array element contains.
  • {{@index}} is a special data variable that gives the index of the current iteration (starting from 0 for the first item). In the example, if an item is the first in the list, @index is 0, so it will display "Item 0: ...". (See the Data Variables section for more about @index and similar variables.)

If the array is empty or not present, by default nothing will be rendered inside the each. You can provide an {{else}}section to handle the "empty list" case​:

{{#each borrower_table}}
  <p>{{name}} – {{id}}</p>
{{else}}
  <p>No items found.</p>
{{/each}}

Here, if borrower_table has no elements, the message "No items found." will be displayed instead of the list. This ensures your template doesn’t just output a blank area when there’s no data.Iterating over objects: If you use #each on an object (for example, an address object), it will iterate over that object's own enumerable properties. In this case, you can use the @key data variable inside the loop to get the property name​:

{{#each borrower_home_address}}
  <p>{{@key}}: {{this}}</p>
{{/each}}

If borrower_home_address is { "street_name": "Main St", "city": "Metropolis" }, this loop would output:

street_name: Main St  
city: Metropolis

Each iteration sets {{this}} to the property’s value (e.g., "Main St"), and {{@key}} to the property's name (e.g., "street_name"). This is useful for dynamically listing out object fields.

with Helper (Changing Context)

The with helper allows you to dive into a nested object and treat it as the current context within a block​. This means inside the with block, you can reference the object's properties directly without repeating the parent object path. When the block ends, the context returns to the previous scope. For example, consider the borrower_home_address object. Without with, you might write:

<p>Address: {{borrower_home_address.street_name}}, {{borrower_home_address.city}}</p>

Using #with, you can simplify this:

{{#with borrower_home_address}}
  <p>Address: {{street_name}}, {{city}}</p>
{{/with}}

When borrower_home_address exists, the content inside the block will output the street name and city directly. The with block changes the context to borrower_home_address, so {{street_name}} is understood as borrower_home_address.street_name. This makes the template cleaner, especially if you need to use multiple fields of that object. You can also provide an {{else}} section in a with block to handle the case where the value is missing or empty​. For instance:

{{#with borrower_home_address}}
  <p>Address: {{street_name}}, {{city}}</p>
{{else}}
  <p>Address not available.</p>
{{/with}}

In this example, if borrower_home_address is present, the address is shown. If it’s not provided (null or undefined), the template will output "Address not available." instead. This pattern helps in showing fallback content when nested data is missing. Note: The with helper only changes the context within its block; once the {{/with}} is reached, the context goes back to what it was before. Also, if the value passed to with is falsy (e.g., an empty object or null), the with block is skipped and the else (if present) is rendered.

Working with Context

Understanding how HTML Template Engine handles context is important for building templates. Context refers to the current scope of data that template engine is looking at while rendering. Here are some key points and examples on context in the template engine:

Top-level context

When the template begins rendering, the top-level context is the entire data object provided to the template (e.g., an object containing borrower_first_name, borrower_last_name, loan_amount, etc.). At this level, you can access any top-level variable directly. For instance, in the top context, {{borrower_first_name}} will output the first name as shown in the data.

Context inside helpers

Certain block helpers like each and with change the context for their inner block​. When you enter an {{#each}} block, the context shifts to the current item of the iteration. Similarly, inside a {{#with someObject}} block, the context becomes someObject. Other helpers like if and unless do not change the context – they simply conditionally render content, but the context inside an if block remains the same as outside.

Example – context in each:

<p>Borrower: {{borrower_first_name}}</p>
{{#each borrower_table}}
  <p>{{borrower_first_name}} – Item ID: {{id}}</p>
{{/each}}

In this example, outside the each, borrower_first_name is directly available (top-level context). Inside the each block, the context is now each element of borrower_table. If each element has an id field, {{id}} outputs that. However, borrower_first_name is not a property of the item in borrower_table. To access the outer context (the borrower’s first name) from inside the loop, you need to reference the parent context. This is done by prefixing the variable with ../. For instance, use {{../borrower_first_name}} inside the each to go “up” one level and get the value from the parent context

Revised example with parent context reference:

{{#each borrower_table}}
  <p>{{../borrower_first_name}} – Item ID: {{id}}</p>
{{/each}}

Here, {{../borrower_first_name}} will correctly display the borrower’s first name for each item because ../ tells template engine to look one level up the context stack for borrower_first_name. The id comes from the current item context. In effect, each rendered <p> might look like “Alice – Item ID: 123”, where "Alice" is the outer context’s first name and 123 is the current item’s id.

The this keyword

In any context, {{this}} refers to the entire current context object/value​. This is often used inside each when iterating over an array of simple values. For example, if borrower_table was an array of names (just strings), inside {{#each borrower_table}}, {{this}} would represent the current name string. If the array element is an object, {{this}} would refer to that object (which generally isn’t useful to print directly, but you could pass it to a helper or inspect it). In practice, you’ll typically use the property names (as shown above with {{id}} or {{name}}), but it’s good to know this represents the current context when needed.

Parent and root contexts

We saw above that ../ lets you move up to the parent context. Each ../ moves up one level. So if you are nested multiple levels (for example, inside an each within an each), you can use multiple ../../ segments to climb further up. Template Engine also provides a special data variable @root which always points to the root context (the very top level data) no matter how deep you are. We will cover @root in the next section, but keep in mind it’s another way to access global context.

Context and conditional helpers

As mentioned, #if and #unless do not create a new context. They simply check a value in the current context. This means inside an if block, you can still access both the current context and any outer contexts normally without using ../ (since you haven’t moved into a new object/array context, you are still in the same scope, just conditionally rendering). The rule of thumb is: use ../ only when you are inside a block that changed the context (like each/with)​. If you’re just inside an if or unless, your context hasn’t changed, so {{borrower_first_name}} would still refer to the same value as it did outside the if. (Attempting to use ../ in an if when not needed could actually jump out to a higher context which might not be what you want.)


By keeping track of the context, you can correctly reference the data you need at each point in your template. When in doubt, remember:

  • Same context: just use the variable name.
  • Diving into an object/array: use each or with (context changes to that data).
  • Coming back out: use ../ (or @root for global) to reference something from an outer scope.

Data Variables

HTML Template Engine provides special data variables (prefixed with @) that give you additional information about the current context and iteration. These data variables are read-only and are set by HTML Template Engine automatically, especially during loops. You can use them in your template to make more dynamic decisions or displays. The available data variables in this template are:

@root

This variable represents the root context, i.e. the top-level data object with which the template was executed​. No matter how deep you are inside nested helpers, @root lets you access the global context. For example, {{@root.borrower_first_name}} will always get the first name from the top level of your data, even if you are inside an each or with block. This is useful if you are deeply nested and want to avoid using multiple ../ segments. (In our earlier example, {{../borrower_first_name}} inside one loop could be replaced with {{@root.borrower_first_name}} to directly fetch the top-level value.)

@index

The zero-based index of the current item in an each loop​. This is only relevant inside an {{#each ...}} block iterating over an array. The first iteration has @index = 0, the second has @index = 1, and so on. You can use @index to display numbering or for calculations. For example, you might show a numbered list as in {{@index}}. {{name}} which would render "0. Alice", "1. Bob", etc., for an array of names. Keep in mind that @index resets for each separate each loop (it’s local to that loop’s context).

@first

A boolean that is true on the first iteration of an each loop, and false for all other iterations​. Template engine sets @first = true only for the first item in an array. You can use this to conditionally display something special for the first item. For example, you might add a different CSS class or include a header only before the first item.

{{#each items}}
  {{#if @first}}<div class="first-item">First item:</div>{{/if}}
  <p>{{this}}</p>
{{/each}}

In this snippet below, the “First item:” label will appear once, before the first item’s <p>, because @first is true only at that point.

@last

A boolean that is true on the last iteration of an each loop​. It becomes true when the loop is on its final item. This is useful for tasks like avoiding a trailing comma in a list or adding closing HTML after the last item. For instance:

{{#each tags}}  
  <span>{{this}}{{#unless @last}}, {{/unless}}</span>  
{{/each}}

Here each tag is followed by a comma unless it’s the last tag (we used unless @last to skip the comma for the final item). This way, the list of tags will be comma-separated without an extra comma at the end.

@key

The key name of the current property when iterating over an object with each​. If your each is looping over an object (as opposed to an array), template engine provides @key to tell you the name of the current property.

{{#each borrower_home_address}}
  <p>{{@key}}: {{this}}</p>
{{/each}}

As shown earlier, @key would be "street_name" for the first iteration (with this being "Main St"), then "city" for the next (with this being "Metropolis"), etc. This lets you know which field you’re dealing with when you only have the value (this) otherwise. (When iterating arrays, @key is not typically used – @index serves a similar role for array positions. In object iteration, there is no numeric index, so @key is how you identify the property.)


These @ data variables are available only in relevant contexts (for example, you won’t have @index outside of an each loop, and @first/@last make sense only in loops). They provide a powerful way to make your templates aware of their position in the data. Using data variables, you can write more dynamic templates. For instance, you can highlight the first item, number each entry, or reference the original data context at any depth. Keep in mind that @root is particularly helpful if you pass the template a complex data object; it ensures you can always access any top-level property without worrying about how deep you are in block helpers.