How to use Handlebars.js for templating
Handlebars Templating Library: an easy-to-use introductory guide
Sometimes, we need to display the same basic HTML, but with some customized data interspersed here and there. The Handlebars.js library is perfect for this. It takes less than 5 minutes to learn how to use this simple and efficient templating tool.
Here are the 7 basic steps.
Steps
- In your HTML file…
- Include the handlebars.js library file in your
<head>
tag - Include your own custom js file just before the closing
</body>
tag - Create the template HTML inside
<script type="text/x-handlebars"></script>
tags
- In your custom JS file…
- Capture the template HTML as a string
- Create a function to generate template instances using
Handlebars.compile()
and the string from the previous step - Create an instance of the template using the function and an object literal
- Incorporate the template instance into a DOM element
In HTML File
1. Include the handlebars.js library file
<head>
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
</head>
2. Include your own custom .js file
<body>
... some stuff
<div id="template1area"></div>
... some stuff
<script src="myHandlebars.js"></script>
</body>
Alternatively, instead of including the custom file just before your closing </body>
tag, you can also include it right after the handlebars.js library in the <head>
tag above, but just make sure you nest your code inside an event listener that fires after the DOM is fully loaded.
It’s important that your custom .js file loads after both the handlebars.js library and the DOM, since we’ll need to reference and add to existing DOM elements.
Note: the template1area <div>
will only be relevant and needed for the last step: step 7.
3. Create the template HTML
<script id="template1" type="text/x-handlebars">
<h2>{{name}}</h2>
{{#if category}}
<strong>Category: </strong> {{category}}<br>
{{/if}}
<strong>Link: </strong>
{{#if link}}
<a href ="{{link}}">{{link}}</a>
{{else}}
none
{{/if}}
<p>
{{#if miscellaneous}}
{{{miscellaneous}}}
{{/if}}
</p>
</script>
Several things to point out here:
- The main functional advantage of wrapping the template HTML inside of this specific type of
<script>
tag is that we do not display the contents of the template HTML, nor try to run it as JavaScript. We could have instead wrapped it inside a<div>
and made sure thedisplay
was set tonone
, but that may cause some unintended consequences later and is considered bad practice. The point is just that there is nothing particularly special about this wrapper, and we care more about what’s inside of it. But using the specific type of<script>
tag, as we’ve done here, more explicitly lets other developers know what the content of the wrapper is supposed to be used for. - Notice that we use two different types of curly braces that will contain customizable data: double curlies
{{ something }}
, and tripple curlies{{{ somethingElse }}}
. The former will rendersomething
as text, and the latter will parsesomethingElse
as HTML content. - We can place the code above anywhere inside our
<body>
tags, but not after. - Note that we can use conditional logic inside the template with
#if
.
In custom JS File (e.g. myHandlebars.js)
4. Capture the template HTML as a string
let template1 = document.querySelector("#template1").innerHTML;
Note: Although we could directly create our template1
string right here instead of defining the HTML template in our HTML file (step 3) and having to capture it here, this approach is better because it better adheres to the separation of concerns principle.
Namely: most of your HTML should be in your HTML file, most of your styling in your CSS file, and most of your logic and behavior in your JS file.
5. Create a function using Handlebars.compile()
let template1Func = Handlebars.compile(template1);
This is essentially the kernel of magic that the the Handlebars library provides. Call Handlebars.compile()
with a string that contains a template that resembles step 3 (i.e. with the curly braces that look like handlebar mustaches), and it will return a smart function you can use to create any instance/customized version of the template you want.
We’ll see an example of that next.
6. Create an instance of the template
let temp1obj1 = {
name: "Vahid's Blog",
category: "Technical blog",
link: "https://vahid.blog",
miscellaneous:
"This part here can incorporate HTML tags
like <strong>strong</strong> and <em>em</em>
because the template displays it using triple curlies.",
};
let temp1FromObj1 = template1Func(temp1obj1);
The object containing our customized data (that we use as an argument passed to the template function) can be either a JS object literal, like temp1obj1
above, or a JSON object.
The function returns a string containing the customized HTML from the template1
template filled in with the temp1obj1
data, representing an instance of the template. This string is captured by the temp1FromObj1
variable.
7. Incorporate the template instance
document.querySelector("#template1area").innerHTML = temp1FromObj1;
Of course, you can incorporate the instance into any element you want, including the document.body itself, or a new element entirely. Just make sure to attach it to the DOM.
And that’s it! There’s a lot more you can do within Handlebars templates, including iterators, partials, and targeting nested objects and their properties. Check out the docs for more info.
Special thanks to Alex Strick, whose post was helpful in getting me started on Handlebars.