handlebars-layouts
Handlebars helpers which implement layout blocks similar to Jade, Jinja, Nunjucks, Swig, and Twig.
Install
With Node.js:
$ npm install handlebars-layouts
With Bower:
$ bower install shannonmoeller/handlebars-layouts
API
Helpers are generated by passing in your instance of Handlebars. This allows you to selectively register the helpers on various instances of Handlebars.
layouts(handlebars) : Object
handlebars
Handlebars
- An instance of Handlebars.
Generates an object containing the layout helpers suitible for passing into registerHelper
.
var handlebars = layouts = ; handlebars;
layouts.register(handlebars) : Object
handlebars
Handlebars
- An instance of Handlebars.
Both generates an object containing the layout helpers and registers them with Handlebars automatically.
var handlebars = layouts = ; layouts;
Helpers
{{#extend [partial] [context] [key=value ...]}}
partial
String
- Name of partial to render.context
Object
(Optional) - A custom context for the partial.attributes
Object
(Optional) - Arbitrary values that will be added to the partial data context.
Loads a layout partial of a given name and defines block content.
{{#extend "layout" foo="bar"}} {{#content "title" mode="prepend"}}Example - {{/content}}{{/extend}}
The {{#extend}}
helper allows you to reason about your layouts as you would class extension where the above is equivalent to the following psuedo code:
{ thisfoo = 'bar'; } { return 'Example - ' + super; }
{{#embed [partial] [context] [key=value ...]}}
partial
String
- Name of partial to render.context
Object
(Optional) - A custom context for the partial.attributes
Object
(Optional) - Arbitrary values that will be added to the partial data context.
Allows you to load a partial which itself extends from a layout. Blocks defined in embedded partials will not conflict with those in the primary layout.
{{#extend "layout"}} {{#content "body"}} {{#embed "gallery"}} {{#content "body"}} <img src="1.png" alt="" /> <img src="2.png" alt="" /> {{/content}} {{/embed}} {{#embed "modal" foo="bar" name=user.fullName}} {{#content "title" mode="prepend"}}Image 1 - {{/content}} {{#content "body"}}<img src="1.png" alt="" />{{/content}} {{/embed}} {{/content}} {{/extend}}
The {{#embed}}
helper allows you to reason about your partials as you would class instantiation where the above is equivalent to the following psuedo code:
{ var gallery = ; gallery; var modal = foo: 'bar' name: thisuserfullName ; modal; modal; return gallery + modal; }
{{#block [name]}}
name
String
- Block identifier.
Defines a named block, with optional default content. Blocks may have content appended, prepended, or replaced entirely when extending or embedding. You may append and prepend to the same block multiple times.
{{#block "header"}} <h1>Hello World</h1>{{/block}} {{#block "main"}} <p>Lorem ipsum...</p>{{/block}} {{#block "footer"}} <p>© 1970</p>{{/block}}
{{#content [name] mode="(append|prepend|replace)"}}
name
String
- Identifier of the block to modify.mode
String
(Optional) - Means of providing block content. Default:replace
.
Sets block content, optionally appending or prepending using the mode
attribute.
Layout:
... {{#block "header"}} Hello World {{/block}} {{#block "main"}} Lorem ipsum. {{/block}} {{#block "footer"}} © 1999 {{/block}}
Page:
{{#extend "layout"}} {{#content "header"}} <h1>Goodnight Moon</h1> {{/content}} {{#content "main" mode="append"}} <p>Dolor sit amet.</p> {{/content}} {{#content "footer" mode="prepend"}} <p>MIT License</p> {{/content}} {{/extend}}
Output:
... Goodnight Moon Lorem ipsum. Dolor sit amet. MIT License © 1999
Conditional Blocks
There are times where you need to wrap a block with an element or use a different class depending on whether content has been provided for a block. For this purpose, the content
helper may be called as a subexpression to check whether content has been provided for a block.
For example, you may wish to have an optional column in a grid layout:
{{!-- layout.hbs --}}<div class="grid"> <div class="grid-col {{#if (content "right")}}grid-col_2of3{{else}}grid-col_full{{/if}}"> {{{block "left"}}} </div> {{#if (content "right")}} <div class="grid-col grid-col_1of3"> {{{block "right"}}} </div> {{/if}}</div>
For a page that only needs a left column, you may omit defining content for the right
block:
{{!-- page.html --}}{{#extend "layout"}} {{#content "left"}} <p>Left</p> {{/content}} {{/extend}}
Resulting in:
Left
For a page with two columns, simply define content for both blocks:
{{!-- page.html --}}{{#extend "layout"}} {{#content "left"}} <p>Left</p> {{/content}} {{#content "right"}} <p>Right</p> {{/content}} {{/extend}}
Resulting in:
Left Right
Example
layout.hbs
{{#block "head"}} {{title}} {{/block}} {{#block "header"}} {{title}} {{/block}} {{#block "body"}} Hello World {{/block}} {{#block "footer"}} © 2013 {{/block}} {{#block "foot"}} {{/block}}
page.html
{{#extend "layout"}} {{#content "head" mode="append"}} <link rel="stylesheet" href="assets/css/home.css" /> {{/content}} {{#content "body"}} <h2>Welcome Home</h2> <ul> {{#items}} <li>{{.}}</li> {{/items}} </ul> {{/content}} {{#content "foot" mode="prepend"}} <script src="assets/js/analytics.js"></script> {{/content}}{{/extend}}
Putting Them Together
var handlebars = ;var layouts = ; // Register helpershandlebars; // Register partialshandlebars; // Compile templatevar template = handlebars; // Render templatevar output = ; console;
Output (prettified for readability)
Layout Test Layout Test Welcome Home apple orange banana © 2013
Contribute
Standards for this project, including tests, code coverage, and semantics are enforced with a build tool. Pull requests must include passing tests with 100% code coverage and no linting errors.
Test
$ npm test
© 2015 Shannon Moeller me@shannonmoeller.com
Licensed under MIT