Handlebars

What is Handlebars?

The official Handlebars logo, borrowed from https://handlebarsjs.comThe official Handlebars logo, borrowed from https://handlebarsjs.com

The official Handlebars logo, borrowed from https://handlebarsjs.com

Handlebars is a templating engine for websites and web applications. Liftoff utilizes Handlebars for site layouts, content presentation, and various types of display logic within a site, including the display of Records-driven content.

📘

Additional reading

The primary use case for Handlebars within Liftoff is the presentation of record-based content. It is recommended that you have an understanding of Liftoff's Records system before attempting to utilize Handlebars to present data within a content block or within a layout.

Handlebars terminology

Handlebars is the templating system itself. A single bit of Handlebars markup is called an expression. Expressions may take the form of an identifier, which outputs a specific bit of information; an iterator or loop, which is used to display multiple sets of identifiers at once; or a logic control or conditional.

Identifier expressions

A basic Handlebars expression using an identifier takes the form of the identifier's name, encased inside two sets of curly braces (sometimes called "Mustaches" when dealing with Handlebars and similar templating systems).

<h1>{{title}}</h1>

In the above example, the value stored in the identifier named title would be output inside the <h1> HTML element. If the stored value of title were, for example, "My Wonder Emporium," then the final output would be <h1>My Wonder Emporium</h1>, which would render in the browser as

My Wonder Emporium

📘

Adding comments

HTML comments take the form of:
<!-- my comment here -->

Handlebars comments take the form of:
{{!-- my comment here --}}

Escaping HTML with single or double "mustaches"

Often within Liftoff, you will be working with data that contains existing HTML markup, such as when you work with a record set containing an HTML field type. In these situations, it is necessary to utilize a "triple mustache" (e.g., {{{identifierNameHere}}}) instead of the normal double mustache to avoid escaping (rendering literally with all the markup shown as actual text) the HTML.

Consider the following example:

<section>{{myContent}}</section>

<section>{{{myContent}}}</section>
<p>This is <strong>really</strong> cool.</p>

When using the double mustache syntax, the output would be:

<p>This is <strong>really</strong> cool.</p>

However, utilizing the triple-braced syntax would yield:

This is really cool.

Loop / iterator expressions

When you want to display multiple items from a set of data using Handlebars, utilize a loop / iterator expression. These expressions use a syntax similar to identifiers, as well as HTML tags, with both an opening and closing "mustache."

As an example, assume that you have created a record type in Liftoff to store data about upcoming events. It contains data for five upcoming events, with each event containing the following fields:

  • eventTitle (text)
  • eventDate (date)
  • eventMaxParticipants (number)
  • eventImage (image)

To display these items in a normal unordered list (HTML element <ul> for unordered list, and <li> for list items), you would first write your loop expression:

{{#records.myEvents_created_asc_all}}

{{/records.myEvents_created_asc_all}}

Since you don't want to create an entirely new unordered list for each item, the tags for the <ul> element go on the outside of your expression:

<ul>
{{#records.myEvents_created_asc_all}}

{{/records.myEvents_created_asc_all}}
</ul>

Since we want to create a list item (<li>) for each event, we place this inside the expression:

<ul>
{{#records.myEvents_created_asc_all}}
  <li></li>
{{/records.myEvents_created_asc_all}}
</ul>

Finally, we can include identifiers for each of the fields in the record type within the <li></li> element tags:

<ul>
{{#records.myEvents_created_asc_all}}
  <li>Join us for {{eventTitle}} on {{eventDate}}. {{eventMaxParticipants}} seats are available. <img src="{{eventImage}}"></li>
{{/records.myEvents_created_asc_all}}
</ul>

When the system renders this content, the browser will see something like the following:

<ul>
  <li>Join us for THANKSGIVING DINNER on 11/25/2019. 25 seats are available. <img src="//unsplash.it/100/100"></li>
  <li>Join us for BOXING DAY on 12/26/2019. 100 seats are available. <img src="//unsplash.it/150/150"></li>
  <!-- additional list items -->
</ul>

When the user visits the page, this would be rendered as something like the following:

  • Join us for THANKSGIVING DINNER on November 25th. 25 seats are available.
  • Join us for BOXING DAY on December 26th. 100 seats are available.

Logic / conditional expressions

Liftoff implements two basic logic structures from Handlebars: IF and UNLESS.

An {{#if}} expression renders the content inside if the provided identifier has any non-false value or content, and may contain an {{else}} clause, providing a fallback for what to display if the condition is not truthy.

Example: If an identifier named showMe had no value, then {{#if showMe}} a {{else}} b {{/if}} would render b. If showMe had any value at all, a would be shown instead.

The {{#unless}} expression acts oppositely to the {{#if}}. It will only show the content unless the condition is true. Using the same example of showMe above, {{#unless showMe}} I'm hidden {{else}} I'm not hidden {{/unless}} would render I'm Hidden if showMe is falsy, and I'm not hidden if its value is truthy.

Nesting if and unless

It is possible to nest multiple logical expressions for greater control over presentation.

Consider the following contrived example for a better understanding of how this might be used in practice:

{{!-- If myData is not empty }}
{{#if myData}}
  {{!-- then for each item in myData do the following --}}
  {{#each myData}}
  <a href="{{url}}">
    {{#unless name}}
      {{!-- if there's no name provided, indicate as much --}}
      NO NAME PROVIDED
    {{else}}
      {{!-- otherwise show the name --}}
      {{name}}
    {{/unless}}
  </a>
  {{/each}}
{{/if}}

Additional reading

For a more indepth, technical explanation of how Handlebars works, we suggest reviewing the official Handlebars documentation. Do note that not all features of the Handlebars system (such as helpers, precompilation, etc.) are available for content display use within Liftoff. As always, if you have any questions, don't hesitate to reach out to us!