Logic-less templates in Handlebars.js are fantastic when you are making templates for JavaScript components, or doing code generation using JavaScript. Handlebars is easy to use, and its features are necessarily limited. One feature that is really missing is recursion. Although Handlebars a helper for traversing an array, it is difficult to implement recursion with, let alone recursion with a depth level. In this guide we’ll show you how to implement recursion with a depth level in Handlebars.js.

Let’s look at the ordinary #each block helper in Handlebars.js first. If we compile the following simple template:

{{#each people}}
{{{this.firstname}}} - {{{this.lastname}}} 
{{/each}}

Then we can execute it like so:

var people = [
  { firstname: "John", lastname: "Smith" },
  { firstname: "Mary", lastname: "Robinson" }
];

Handlebars.templates.people({ people: people });

Using Handlebars Partials

What if we had the following model:

var people = [
  { firstname: "John", lastname: "Smith", friends: [
      { firstname: "Manuel", lastname: "Ortega", friends: [
        { firstname: "Max", lastname: "Kowalski", friends: [] },
        { firstname: "Don", lastname: "River", friends: [] }
      ]}
  ]}, 
  { firstname: "Mary", lastname: "Robinson", friends: [] } 
];

Here, each person has an array of friends, and each friend has their own array of friends. Suppose we’d like to render these relationships as an HTML unordered list:

<ul>
  <li>John Smith
    <ul>
      <li>Manuel Ortega
        <ul>
          <li>Max Kowalski</li>
          <li>Don River</li>
        </ul>
      </li>
    </ul>
  <li>Mary Robinson</li>
</ul>

This will require recursion.

We can combine the #each block helper with partial templates. When we have the partial template call itself, then we have recursion. A partial template for a person looks like this:

<li>
  {{{this.firstname}}} {{{this.lastname}}}
  <ul>
    {{#each this.friends}}
      {{> person}}
    {{/each}}
  </ul>
</li>

And our main template is:

<ul>
  {{#each people}}
  {{> person}}
  {{/each}}
</ul>

We’ll need to register our partial before we can render the main template. In JavaScript:

Handlebars.registerPartial('person', Handlebars.templates.person);
Handlebars.templates.people({ people: people });

Using a Recursion Helper

We’ll keep the same model, but we would like to render a different output this time:

+ John Smith
++ Manuel Ortega
+++ Max Kowalski
+++ Don River
+ Mary Robinson

In order to render the pluses, our Handlebars templates needs to know what the recursion depth is at any given time, and we don’t have access to this information when using the #each block helper and a partial. However, we can still solve this by creating our own custom helper:

buildPerson(person, level) {
  if(!level) level = 1;
  var str = "";
  for (let i = 0; i < level; i++) str += "+";
  str += Handlebars.templates.person({ person: person });
  person.friends.forEach((o) => {
    str = str + this.buildObject(o, level+1);
  });
  return new Handlebars.SafeString(str);
}

Handlebars.registerHelper('buildPerson', (person) => { return buildPerson(person); });

(Note that the custom helper returns a Handlebars SafeString to prevent Handlebars from HTML escaping the names of the people, should they contain escapable characters.)

This custom helper takes a person object and a recursion depth level. By default, the depth level will be 1, resulting in one plus sign. The helper calls a partial, which renders one person (ignoring their friends). It then calls itself recursively for the person’s friends, increasing the recursion depth by 1.

Our main template becomes:

{{#each people}}
{{buildPerson this}}
{{/each}}

And our partial becomes:

{{{person.firstname}}} {{{person.lastname}}}

This strategy allows us to implement recursion with depth level.