Layouts and partials
Fluid's layout system —
<f:,
<f:, and
<f: — is one of the first things developers look for
when switching template engines. EXT:handlebars ships an equivalent mechanism
implemented as the extend, block, and content helpers, modelled
after the handlebars-layouts
convention.
How the systems compare
Fluid uses a push model: a child template declares which layout it inherits and then pushes named sections into the layout's named slots. Handlebars uses the same model, but the building blocks are ordinary helpers rather than dedicated language constructs.
| Fluid | Handlebars |
|---|---|
<f: | { |
<f: (in layout) | { |
<f: (in template) | { |
The content helper supports an optional mode hash argument
(replace / append / prepend) that controls
how the child's content is merged with the layout block's default. replace
is the default and matches Fluid's behaviour.
Side-by-side example
Layout file — Fluid:
<!DOCTYPE html>
<html>
<head>
<f:render section="Head" optional="true" />
</head>
<body>
<header>
<f:render section="Header" />
</header>
<main>
<f:render section="Main" />
</main>
<footer>
<f:render section="Footer" optional="true" />
</footer>
</body>
</html>
Layout file — Handlebars:
<!DOCTYPE html>
<html>
<head>
{{#block "head"}}{{/block}}
</head>
<body>
<header>
{{#block "header"}}{{/block}}
</header>
<main>
{{#block "main"}}{{/block}}
</main>
<footer>
{{#block "footer"}}{{/block}}
</footer>
</body>
</html>
Child template — Fluid:
<f:layout name="Main" />
<f:section name="Head">
<title>{header}</title>
</f:section>
<f:section name="Header">
<h1>{header}</h1>
</f:section>
<f:section name="Main">
<p>{bodytext}</p>
</f:section>
Child template — Handlebars:
{{#extend "Main"}}
{{#content "head"}}
<title>{{header}}</title>
{{/content}}
{{#content "header"}}
<h1>{{header}}</h1>
{{/content}}
{{#content "main"}}
<p>{{bodytext}}</p>
{{/content}}
{{/extend}}
Note
Handlebars layouts are resolved as partials, so the layout file must be
placed in one of the configured partial root paths, not in the template root
paths. By convention, default. lives under
Resources/.
Default content in blocks
A { can hold default markup that is used verbatim when
the child provides no matching { for that slot. This is
the equivalent of Fluid's
optional="true" on
<f:
combined with a fallback in the layout.
<footer>
{{#block "footer"}}
<p>© {{year}} My Site</p>
{{/block}}
</footer>
A child template that does not declare a { block
will render the default copyright line automatically.
Appending and prepending content
The mode argument lets a child add to a block rather than replace
it. This has no direct Fluid equivalent and is often used for accumulating
<script> or
<link> tags:
{{#extend "Main"}}
{{#content "head" mode="append"}}
<link rel="stylesheet" href="/assets/my-element.css">
{{/content}}
{{#content "main"}}
…
{{/content}}
{{/extend}}
Using partials without a layout
Not every template needs a full layout. Reusable snippets that were Fluid
partials map directly to Handlebars partials with no extra ceremony — just
create a .hbs file in the partial root path and include it with
{.
See also
- Partials — partial inclusion syntax
- Template paths — how to configure partial root paths