{"id":13438954,"url":"https://github.com/shannonmoeller/handlebars-layouts","last_synced_at":"2025-05-16T15:07:00.827Z","repository":{"id":41309011,"uuid":"11223921","full_name":"shannonmoeller/handlebars-layouts","owner":"shannonmoeller","description":"Handlebars helpers which implement layout blocks similar to Jinja, Nunjucks (Swig), Pug (Jade), and Twig.","archived":false,"fork":false,"pushed_at":"2019-07-05T10:22:45.000Z","size":419,"stargazers_count":363,"open_issues_count":5,"forks_count":29,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-12T12:08:55.173Z","etag":null,"topics":["blocks","embed","handlebars","layout","layouts","nodejs","partials","templating"],"latest_commit_sha":null,"homepage":"http://npm.im/handlebars-layouts","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shannonmoeller.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-06T20:21:59.000Z","updated_at":"2025-02-18T04:13:03.000Z","dependencies_parsed_at":"2022-08-04T17:30:34.321Z","dependency_job_id":null,"html_url":"https://github.com/shannonmoeller/handlebars-layouts","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shannonmoeller%2Fhandlebars-layouts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shannonmoeller%2Fhandlebars-layouts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shannonmoeller%2Fhandlebars-layouts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shannonmoeller%2Fhandlebars-layouts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shannonmoeller","download_url":"https://codeload.github.com/shannonmoeller/handlebars-layouts/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254553959,"owners_count":22090417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blocks","embed","handlebars","layout","layouts","nodejs","partials","templating"],"created_at":"2024-07-31T03:01:09.936Z","updated_at":"2025-05-16T15:07:00.783Z","avatar_url":"https://github.com/shannonmoeller.png","language":"JavaScript","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# `handlebars-layouts`\n\n[![NPM version][npm-img]][npm-url] [![Downloads][downloads-img]][npm-url] [![Build Status][travis-img]][travis-url] [![Coverage Status][coveralls-img]][coveralls-url] [![Tip][amazon-img]][amazon-url]\n\nHandlebars helpers which implement layout blocks similar to Jade, Jinja, Nunjucks, Swig, and Twig.\n\n## Install\n\nWith [Node.js](http://nodejs.org):\n\n    $ npm install handlebars-layouts\n\nWith [Bower](http://bower.io):\n\n    $ bower install shannonmoeller/handlebars-layouts\n\n## API\n\nHelpers are generated by passing in your instance of Handlebars. This allows you to selectively register the helpers on various instances of Handlebars.\n\n### `layouts(handlebars) : Object`\n\n- `handlebars` `Handlebars` - An instance of Handlebars.\n\nGenerates an object containing the layout helpers suitible for passing into `registerHelper`.\n\n```js\nvar handlebars = require('handlebars'),\n    layouts = require('handlebars-layouts');\n\nhandlebars.registerHelper(layouts(handlebars));\n```\n\n### `layouts.register(handlebars) : Object`\n\n- `handlebars` `Handlebars` - An instance of Handlebars.\n\nBoth generates an object containing the layout helpers and registers them with Handlebars automatically.\n\n```js\nvar handlebars = require('handlebars'),\n    layouts = require('handlebars-layouts');\n\nlayouts.register(handlebars);\n```\n\n## Helpers\n\n### `{{#extend [partial] [context] [key=value ...]}}`\n\n- `partial` `String` - Name of partial to render.\n- `context` `Object` _(Optional)_ - A custom context for the partial.\n- `attributes` `Object` _(Optional)_ - Arbitrary values that will be added to the partial data context.\n\nLoads a layout partial of a given name and defines block content.\n\n```handlebars\n{{#extend \"layout\" foo=\"bar\"}}\n    {{#content \"title\" mode=\"prepend\"}}Example - {{/content}}\n{{/extend}}\n```\n\nThe `{{#extend}}` helper allows you to reason about your layouts as you would class extension where the above is equivalent to the following psuedo code:\n\n```js\nclass Page extends Layout {\n    constructor() {\n        this.foo = 'bar';\n    }\n\n    title() {\n        return 'Example - ' + super();\n    }\n}\n```\n\n### `{{#embed [partial] [context] [key=value ...]}}`\n\n- `partial` `String` - Name of partial to render.\n- `context` `Object` _(Optional)_ - A custom context for the partial.\n- `attributes` `Object` _(Optional)_ - Arbitrary values that will be added to the partial data context.\n\nAllows 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.\n\n```handlebars\n{{#extend \"layout\"}}\n\n    {{#content \"body\"}}\n        {{#embed \"gallery\"}}\n            {{#content \"body\"}}\n                \u003cimg src=\"1.png\" alt=\"\" /\u003e\n                \u003cimg src=\"2.png\" alt=\"\" /\u003e\n            {{/content}}\n        {{/embed}}\n\n        {{#embed \"modal\" foo=\"bar\" name=user.fullName}}\n            {{#content \"title\" mode=\"prepend\"}}Image 1 - {{/content}}\n            {{#content \"body\"}}\u003cimg src=\"1.png\" alt=\"\" /\u003e{{/content}}\n        {{/embed}}\n    {{/content}}\n\n{{/extend}}\n```\n\nThe `{{#embed}}` helper allows you to reason about your partials as you would class instantiation where the above is equivalent to the following psuedo code:\n\n```js\nclass Page extends Layout {\n    body() {\n        var gallery = new Gallery();\n\n        gallery.replaceBody('\u003cimg src=\"1.png\" alt=\"\" /\u003e\\n\u003cimg src=\"2.png\" alt=\"\" /\u003e');\n\n        var modal = new Modal({\n            foo: 'bar',\n            name: this.user.fullName\n        });\n\n        modal.prependTitle('Image 1 - ');\n        modal.replaceBody('\u003cimg src=\"1.png\" alt=\"\" /\u003e');\n\n        return gallery.toString() + modal.toString();\n    }\n}\n```\n\n### `{{#block [name]}}`\n\n- `name` `String` - Block identifier.\n\nDefines 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.\n\n```handlebars\n{{#block \"header\"}}\n    \u003ch1\u003eHello World\u003c/h1\u003e\n{{/block}}\n\n{{#block \"main\"}}\n    \u003cp\u003eLorem ipsum...\u003c/p\u003e\n{{/block}}\n\n{{#block \"footer\"}}\n    \u003cp\u003e\u0026copy; 1970\u003c/p\u003e\n{{/block}}\n```\n\n### `{{#content [name] mode=\"(append|prepend|replace)\"}}`\n\n- `name` `String` - Identifier of the block to modify.\n- `mode` `String` _(Optional)_ - Means of providing block content. Default: `replace`.\n\nSets block content, optionally appending or prepending using the `mode` attribute.\n\nLayout:\n\n```handlebars\n\u003chtml\u003e\n    ...\n    \u003cbody\u003e\n        {{#block \"header\"}}\n            \u003ch1\u003eHello World\u003c/h1\u003e\n        {{/block}}\n\n        {{#block \"main\"}}\n            \u003cp\u003eLorem ipsum.\u003c/p\u003e\n        {{/block}}\n\n        {{#block \"footer\"}}\n            \u003cp\u003e\u0026copy; 1999\u003c/p\u003e\n        {{/block}}\n    \u003c/body\u003e\n\u003c/html\u003e\n```\n\nPage:\n\n```handlebars\n{{#extend \"layout\"}}\n\n    {{#content \"header\"}}\n        \u003ch1\u003eGoodnight Moon\u003c/h1\u003e\n    {{/content}}\n\n    {{#content \"main\" mode=\"append\"}}\n        \u003cp\u003eDolor sit amet.\u003c/p\u003e\n    {{/content}}\n\n    {{#content \"footer\" mode=\"prepend\"}}\n        \u003cp\u003eMIT License\u003c/p\u003e\n    {{/content}}\n\n{{/extend}}\n```\n\nOutput:\n\n```handlebars\n\u003chtml\u003e\n    ...\n    \u003cbody\u003e\n        \u003ch1\u003eGoodnight Moon\u003c/h1\u003e\n\n        \u003cp\u003eLorem ipsum.\u003c/p\u003e\n        \u003cp\u003eDolor sit amet.\u003c/p\u003e\n\n        \u003cp\u003eMIT License\u003c/p\u003e\n        \u003cp\u003e\u0026copy; 1999\u003c/p\u003e\n    \u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Conditional Blocks\n\nThere 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](http://handlebarsjs.com/expressions.html#subexpressions) to check whether content has been provided for a block.\n\nFor example, you may wish to have an optional column in a grid layout:\n\n```handlebars\n{{!-- layout.hbs --}}\n\u003cdiv class=\"grid\"\u003e\n    \u003cdiv class=\"grid-col {{#if (content \"right\")}}grid-col_2of3{{else}}grid-col_full{{/if}}\"\u003e\n        {{{block \"left\"}}}\n    \u003c/div\u003e\n    {{#if (content \"right\")}}\n        \u003cdiv class=\"grid-col grid-col_1of3\"\u003e\n            {{{block \"right\"}}}\n        \u003c/div\u003e\n    {{/if}}\n\u003c/div\u003e\n```\n\nFor a page that only needs a left column, you may omit defining content for the `right` block:\n\n```handlebars\n{{!-- page.html --}}\n{{#extend \"layout\"}}\n\n    {{#content \"left\"}}\n        \u003cp\u003eLeft\u003c/p\u003e\n    {{/content}}\n\n{{/extend}}\n```\n\nResulting in:\n\n```html\n\u003cdiv class=\"grid\"\u003e\n    \u003cdiv class=\"grid-col grid-col_full\"\u003e\n        \u003cp\u003eLeft\u003c/p\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\nFor a page with two columns, simply define content for both blocks:\n\n```handlebars\n{{!-- page.html --}}\n{{#extend \"layout\"}}\n\n    {{#content \"left\"}}\n        \u003cp\u003eLeft\u003c/p\u003e\n    {{/content}}\n\n    {{#content \"right\"}}\n        \u003cp\u003eRight\u003c/p\u003e\n    {{/content}}\n\n{{/extend}}\n```\n\nResulting in:\n\n```html\n\u003cdiv class=\"grid\"\u003e\n    \u003cdiv class=\"grid-col grid-col_2of3\"\u003e\n        \u003cp\u003eLeft\u003c/p\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"grid-col grid-col_1of3\"\u003e\n        \u003cp\u003eRight\u003c/p\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\n## Example\n\n### layout.hbs\n\n```handlebars\n\u003c!doctype html\u003e\n\u003chtml lang=\"en-us\"\u003e\n\u003chead\u003e\n    {{#block \"head\"}}\n        \u003ctitle\u003e{{title}}\u003c/title\u003e\n\n        \u003clink rel=\"stylesheet\" href=\"assets/css/screen.css\" /\u003e\n    {{/block}}\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cdiv class=\"site\"\u003e\n        \u003cdiv class=\"site-hd\" role=\"banner\"\u003e\n            {{#block \"header\"}}\n                \u003ch1\u003e{{title}}\u003c/h1\u003e\n            {{/block}}\n        \u003c/div\u003e\n\n        \u003cdiv class=\"site-bd\" role=\"main\"\u003e\n            {{#block \"body\"}}\n                \u003ch2\u003eHello World\u003c/h2\u003e\n            {{/block}}\n        \u003c/div\u003e\n\n        \u003cdiv class=\"site-ft\" role=\"contentinfo\"\u003e\n            {{#block \"footer\"}}\n                \u003csmall\u003e\u0026copy; 2013\u003c/small\u003e\n            {{/block}}\n        \u003c/div\u003e\n    \u003c/div\u003e\n\n    {{#block \"foot\"}}\n        \u003cscript src=\"assets/js/controllers/home.js\"\u003e\u003c/script\u003e\n    {{/block}}\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### page.html\n\n```handlebars\n{{#extend \"layout\"}}\n    {{#content \"head\" mode=\"append\"}}\n        \u003clink rel=\"stylesheet\" href=\"assets/css/home.css\" /\u003e\n    {{/content}}\n\n    {{#content \"body\"}}\n        \u003ch2\u003eWelcome Home\u003c/h2\u003e\n\n        \u003cul\u003e\n            {{#items}}\n                \u003cli\u003e{{.}}\u003c/li\u003e\n            {{/items}}\n        \u003c/ul\u003e\n    {{/content}}\n\n    {{#content \"foot\" mode=\"prepend\"}}\n        \u003cscript src=\"assets/js/analytics.js\"\u003e\u003c/script\u003e\n    {{/content}}\n{{/extend}}\n```\n\n### Putting Them Together\n\n```js\nvar handlebars = require('handlebars');\nvar layouts = require('handlebars-layouts');\n\n// Register helpers\nhandlebars.registerHelper(layouts(handlebars));\n\n// Register partials\nhandlebars.registerPartial('layout', fs.readFileSync('layout.hbs', 'utf8'));\n\n// Compile template\nvar template = handlebars.compile(fs.readFileSync('page.html', 'utf8'));\n\n// Render template\nvar output = template({\n    title: 'Layout Test',\n    items: [\n        'apple',\n        'orange',\n        'banana'\n    ]\n});\n\nconsole.log(output);\n```\n\n### Output (prettified for readability)\n\n```handlebars\n\u003c!doctype html\u003e\n\u003chtml lang=\"en-us\"\u003e\n\u003chead\u003e\n    \u003ctitle\u003eLayout Test\u003c/title\u003e\n\n    \u003clink rel=\"stylesheet\" href=\"assets/css/screen.css\" /\u003e\n    \u003clink rel=\"stylesheet\" href=\"assets/css/home.css\" /\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cdiv class=\"site\"\u003e\n        \u003cdiv class=\"site-hd\" role=\"banner\"\u003e\n            \u003ch1\u003eLayout Test\u003c/h1\u003e\n        \u003c/div\u003e\n\n        \u003cdiv class=\"site-bd\" role=\"main\"\u003e\n            \u003ch2\u003eWelcome Home\u003c/h2\u003e\n            \u003cul\u003e\n                \u003cli\u003eapple\u003c/li\u003e\n                \u003cli\u003eorange\u003c/li\u003e\n                \u003cli\u003ebanana\u003c/li\u003e\n            \u003c/ul\u003e\n        \u003c/div\u003e\n\n        \u003cdiv class=\"site-ft\" role=\"contentinfo\"\u003e\n            \u003csmall\u003e\u0026copy; 2013\u003c/small\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003cscript src=\"assets/js/analytics.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"assets/js/controllers/home.js\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Contribute\n\nStandards 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.\n\n## Test\n\n    $ npm test\n\n----\n\nMIT © [Shannon Moeller](http://shannonmoeller.com)\n\n[amazon-img]:    https://img.shields.io/badge/tip-jar-yellow.svg?style=flat-square\n[amazon-url]:    https://www.amazon.com/gp/registry/wishlist/1VQM9ID04YPC5?sort=universal-price\n[coveralls-img]: http://img.shields.io/coveralls/shannonmoeller/handlebars-layouts/master.svg?style=flat-square\n[coveralls-url]: https://coveralls.io/r/shannonmoeller/handlebars-layouts\n[downloads-img]: http://img.shields.io/npm/dm/handlebars-layouts.svg?style=flat-square\n[npm-img]:       http://img.shields.io/npm/v/handlebars-layouts.svg?style=flat-square\n[npm-url]:       https://npmjs.org/package/handlebars-layouts\n[travis-img]:    http://img.shields.io/travis/shannonmoeller/handlebars-layouts/master.svg?style=flat-square\n[travis-url]:    https://travis-ci.org/shannonmoeller/handlebars-layouts\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshannonmoeller%2Fhandlebars-layouts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshannonmoeller%2Fhandlebars-layouts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshannonmoeller%2Fhandlebars-layouts/lists"}