Leafpub templates are built with a simple but powerful template system called Handlebars. Handlebars was created in 2010 as superset of the Mustache template system, which popularized the use of curly brackets for placeholders.

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

Handlebars builds on this concept by adding simple logic and extensibility through the use of helpers. This post will introduce you to the Handlebars syntax and explain how data is made available to page templates.

Syntax

A Handlebars template is nothing more than an HTML document with one or more Handlebars expressions mixed in. Here's how you might display the post title, featured image, and content in your template:

<h2 class="post-title">
{{title}}
</h2>

{{#if image}}
<figure class="featured-image">
<img src="...">
</figure>
{{/if}}

<div class="post-content">
{{content}}
</div>

Every Handlebars expression is wrapped in curly brackets so they're easy to identify. Each expression can contain either a property or a helper.

Properties

To output a property, simply wrap it in curly brackets:

<h2 class="post-title">
{{title}}
</h2>

Tip: With Handlebars, you don't have to worry about escaping HTML. Handlebars takes care of that for you!

Some properties contain a collection (or array) of data. For example, an author property has a name, email address, avatar, bio, etc. To access a specific property in a collection, use a dot:

<div class="author-name">
{{author.name}}
</div>

Ok, that covers the very basics of properties. Let's take a look at how helpers work!

Helpers

Helpers add logic and functionality to your templates. They share a similar syntax to properties, but many also support arguments to pass in data and attributes to change the way helpers work. Handlebars provides some powerful default helpers and Leafpub builds on that foundation by adding a ton of its own custom helpers.

In the previous example, we used an if helper to check for the image property. This is called a block helper since it has an opening and a closing tag:

{{#if image}}
<figure class="featured-image">
<img src="...">
</figure>
{{/if}}

In this example, if is the helper and image is an argument. It would read like this in English:

If the image property contains a value, output this HTML to show the featured image.

Some helpers support attributes. For example, the date helper can show the date in a custom format:

<div class="post-date">
Posted on {{date format="%b %e, %Y"}}
</div>

In this case, date is the helper and format is an attribute. The syntax for helper attributes is very much the same as that of HTML attributes. You'll also notice that there isn't a closing tag for this one, which means it's not a block helper.

Tip: It's important to know that helpers can have both arguments and attributes. Think of it this way: an argument is data that gets passed into a helper, whereas an attribute is a key/value pair typically used to configure the helper.

Contexts

Now that you have a basic understanding of how to output content into a template, let's talk about where the data for those templates comes from.

The Root Context

When a webpage is requested, Leafpub determines which template it should use and gathers the appropriate data to render it. The data is provided to the template in what we call the root context. For example, here's the data a blog post will receive:

@root
- post
- title
- content
- pub_date
- author
- image
- ...

Based on that, we can tell that the root context contains a post property, which is a collection of data that belongs to the current post. To output the post's title, we can do this:

<h2>{{@root.post.title}}</h2>

But that's somewhat long and verbose, and since templates are rendered in the root context by default, we can simply use this instead:

<h2>{{post.title}}</h2>

Much better. Keep in mind that the two expressions above are identical — they'll both output the same thing!

Changing Contexts

Sometimes it's convenient to change from the root context to another context. Using my previous example, I can change to the @root.post context using a helper:

{{#post}}
<h2>{{title}}</h2>
{{/post}}

Everything inside the post block will be in the post context (i.e. @root.post). That means we can refer to its properties without a prefix now. In this example, the {{title}} property will output the value of @root.post.title. However, once we reach the end tag {{/post}}, we'll be back in the root context again.

This is a really helpful concept when we start working with loops and more complex data sets. For now, just be aware that different contexts exist and you can switch between them in your templates.

Partials

This is a lot to take in, especially for an introductory post, but partials are a really important concept in Handlebars. A partial is essentially an include file. You can pull it into your template any time using a simple syntax:

{{> my-partial}}

This will include my-partial.hbs into your template, and all expressions will be evaluated in the context you are currently in.

Partials are really handy for headers, footers, sidebars, and any other content that will be used by more than one template.

Summary

In this post I talked about the Handlebars syntax, what helpers are and how they work, how data contexts are provided to templates, and how partials can be used to include content fragments into templates.

That should be enough to get you tinkering, but if you'd like to read more about Handlebars, check out the official Handlebars documentation or the LightnCandy docs for additional information.