Pattern nesting with Handlebars Layouts

Introduction

Pattern libraries are useful tools that help assist with the organization and swift development of patterns. A pattern library that is driven via Handlebars templating can be greatly enhanced by using layout blocks to template and nest patterns with. In particular, the handlebars-layouts library can be used for this reason.

One organizational schema that is useful in pattern libraries follows the structure: Elements -> Components -> Templates -> Pages. Elements are the simplest form of patterns, while pages are the most complete, being composed from other elements, components, and templates. We’ll refer to this schema.

Given our schema, handlebars-layouts allows us to implement the templates. For our templates, we can define a block (or multiple blocks) which designates the area in which we wish to host our other patterns in different variations. Overridable content/patterns may also be placed in the block by default, and when utilizing a template it is optional to define/override this block. This functionality usually allows us to visualize [with placeholders] the different areas of the template that can host patterns.

Installation

The library handlebars-layouts can be installed via a JavaScript package manager. Most popularly via npm with npm install handlebars-layouts.

Depending on the Handlebars driven pattern library, registering the handlebars-layouts library may differ. But, we’ll show an example for registering and using the library with Fractal, a pattern library that can utilize Handlebars as the templating language for patterns.

In fractal.js, we can register the handlebars-layouts library as such:

const handlebarsLayouts = require('handlebars-layouts’);
const instanceComponents = fractal.components.engine();
handlebarsLayouts.register(instanceComponents.handlebars);

Example #1: Base Template

In this first example, we can define a base page template to showcase basic functionality and usage. Our base template (base.hbs) has a block defined as “body“. The “body” block is surrounded by a <main> element, along with a Header and a Footer:

{{ render '@header'}}

<main>
   {{#block "body"}}
      <!— Content that is overridden  —>
      <div class=“placeholder-element”>
          Placeholder for Body Content
      </div>
   {{/block}}
</main>

{{ render '@footer’}}

Next, we’ll define a page (sample-page.hbs) and extend our base template (base.hbs). We can extend the base template to create a page with only some text content:

{{#extend '@base'}}
   {{#content 'body'}}

      <p class="sample-text">Sample page text content</p>

   {{/content}}
{{/extend}}

And as a result, the following HTML will be generated from extending the base template:

<header>[...]</header>

<main>
   <p class="sample-text">Sample page text content</p>
</main>

<footer>[...]</footer>

Example #2: Promo

Promo components are often authored in a CMS and can contain a wide variety of different elements and components. Additionally, Promo components often also have different author-able settings.

To make our sample page more robust, we can define a Promo that extends the same layout block functionality as a template. This allows us to easily and dynamically test out other patterns located inside of the Promo. Additionally, our Promo will accept a boolean option to enable/disable an overlay setting.

In our Promo (promo.hbs), we can label the layout block as “promo-content” and the overlay boolean variable as “promoHasOverlay“:

<div class="promo{{#if promoHasOverlay}} promo--overlay{{/if}}">
   {{#block "promo-content"}}
      <!— Content that is overridden  -->
      <div class=“placeholder-element”>
          Placeholder for Promo Content
      </div>
   {{/block}}
</div>

Given the Promo, we can add it to our sample page, setting the “promoHasOverlay” value to true and including some sample text:

{{#extend '@base'}}
   {{#content 'body'}}

      <p class="sample-text">Sample page text content</p>

      {{#extend '@promo'
                promoHasOverlay=true
      }}
         {{#content 'promo-content'}}
            <p class="sample-text">Sample Promo text content</p>
         {{/content}}
      {{/extend}}

   {{/content}}
{{/extend}}

And given the new Promo, we update our sample page (sample-page.html) with the following HTML:

<header>[...]</header>

<main>
    <p class="sample-text">Sample page text content</p>

    <div class="promo promo--overlay">
        <p class="sample-text">Sample Promo text content</p>
    </div>
</main>

<footer>[...]</footer>

Conclusion

Additional features are available with handlebars-layouts, such as embedding. Otherwise, the above uses of the layout block tooling provide robust functionality by being able to construct patterns from templates.

Leave a Reply

avatar
  Subscribe  
Notify of