---
title: "Writing templates"
manual: "Handlebars"
version: "main"
permalink: "https://docs.typo3.org/permalink/cpsit/typo3-handlebars:templates@main"
source: "Usage/Templates.rst"
rendered: "2026-09-29T09:05:57+00:00"
---

# Writing templates {#templates}

Templates are plain `.hbs` files using the standard
[Handlebars syntax](https://handlebarsjs.com/guide/): expressions, block
helpers such as `{{#if}}` and `{{#each}}`, partials
and comments all work as documented there. This page covers what the
extension adds on top: how template names are resolved, how to build layouts,
and which helpers are available out of the box.

-   [Referencing templates and partials](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:referencing-templates-and-partials@main)
-   [Partials](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:partials@main)
-   [Layouts](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:layouts@main)
-   [Built-in helpers](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:built-in-helpers@main)
-   [Debugging tips](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:debugging-tips@main)

## Referencing templates and partials {#templates-names}

Templates and partials are referenced by name, without the `.hbs` file
extension. They are looked up in the configured
[template and partial root paths](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:template-paths@main). Two addressing styles
are supported.

### Directory-relative names {#templates-names-relative}

A name without prefix is resolved relative to the root paths, just like in
Fluid. `templateName = Blog/List` resolves to
`Blog/List.hbs` in one of the template root paths, and
`{{> Components/Card}}` to `Components/Card.hbs` in one of
the partial root paths.

### Flat names {#template-paths-flat-names}

A name prefixed with `@` is looked up by its bare filename, regardless
of the subdirectory the file lives in:

```typoscript
tt_content.tx_myext_teaser = HANDLEBARSTEMPLATE
tt_content.tx_myext_teaser {
    # Finds e.g. Components/Molecules/teaser.hbs
    templateName = @teaser
}
```

```handlebars
{{> @card}}
```

If the same filename exists in multiple root paths, the root path with the
higher priority wins. This follows the
[Fractal](https://fractal.build/guide/core-concepts/naming.html) naming
convention, so a Fractal component library can be used as template source
without changes.

Appending `--<variant>` selects a named variant. If no dedicated file
exists for the variant, the base name is used instead:

```handlebars
{{> @card--highlighted}}   {{!-- falls back to @card if not found --}}
```

## Partials {#templates-partials}

Partials are included with the standard `{{> name}}` syntax.
Without further arguments, the partial receives the current context. Pass
a different context as positional argument and/or single values as hash
arguments:

```handlebars
{{> @card}}
{{> @card item}}
{{> @card title=item.title image=item.image}}
```

The `render` helper is an alternative that allows passing and
merging contexts explicitly, see [render](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:templates-helpers-render@main).

## Layouts {#templates-layouts}

Layouts are built with the `extend`, `block` and
`content` helpers, modelled after
[handlebars-layouts](https://github.com/shannonmoeller/handlebars-layouts).
A layout is an ordinary partial that declares named slots with
`{{#block}}`. A block may contain default content that is used
if no template fills the slot:

**EXT:my_sitepackage/Resources/Private/Partials/Handlebars/default.hbs**

```handlebars
<main>
    {{#block "main"}}{{/block}}
</main>
<footer>
    {{#block "footer"}}
        <p>&copy; My Site</p>
    {{/block}}
</footer>
```

A template wraps its markup in `{{#extend}}` and fills slots with
`{{#content}}`:

**EXT:my_sitepackage/Resources/Private/Templates/Handlebars/my-element.hbs**

```handlebars
{{#extend "default"}}
    {{#content "main"}}
        <h1>{{header}}</h1>
    {{/content}}
{{/extend}}
```

By default, `{{#content}}` replaces the block's default content.
Pass `mode="append"` or `mode="prepend"` to add to it
instead.

> [!NOTE]
> Layouts are resolved as partials, so layout files must be placed in one of
> the configured partial root paths.

## Built-in helpers {#templates-helpers}

Next to the helpers built into Handlebars itself (`if`,
`unless`, `each`, `with`,
`lookup`, `log`), the extension registers the
following helpers. To add your own, see [Custom helpers](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:custom-helpers@main).

### extend, block, content {#templates-helpers-layout}

Build layouts, see [Layouts](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:templates-layouts@main). `{{#extend}}`
accepts an optional context as second argument and hash arguments, which are
merged into the context passed to the layout.

### render {#templates-helpers-render}

Renders a partial. The first argument is the partial name, the optional second
argument a custom context:

```handlebars
{{render "@card"}}
{{render "@card" item}}
{{render "@card" item merge=true}}
```

Without custom context, the partial receives the root variable named like the
partial itself (e.g. `@card`), if present. This matches how Fractal
provides component contexts. With `merge=true`, the custom context
is merged into this default context instead of replacing it.

### get {#templates-helpers-get}

Reads a property path from an object or array. Unlike plain dot notation, it
supports getter methods and dynamic keys. Paths are resolved the same way as
[variable paths in Fluid templates](https://docs.typo3.org/other/typo3fluid/fluid/main/en-us/Syntax/Variables.html#variable-access-objects):

```handlebars
{{get post "category.title"}}
{{get object dynamicKey}}
```

### join {#templates-helpers-join}

Joins all given values into a string. Values that cannot be converted to a
string are skipped:

```handlebars
{{join firstName lastName separator=" "}}
```

### merge {#templates-helpers-merge}

Merges arrays recursively, with later arrays overriding earlier ones. Hash
arguments are merged last. Mostly used as a subexpression to build a context
for a partial:

```handlebars
{{> @card (merge item highlighted=true)}}
```

### debug {#templates-helpers-debug}

Dumps a value using Extbase's `DebuggerUtility`. Without argument, the
current context is dumped:

```handlebars
{{debug}}
{{debug item title="Current item" maxDepth=3}}
```

### viewHelper, viewHelperNamespace {#templates-helpers-view-helper}

Invokes a Fluid ViewHelper. This is meant as a temporary aid when
[migrating from Fluid](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:migration-from-fluid-helpers-bridge@main):

```handlebars
{{viewHelper "f:format.date" date=someDate format="d.m.Y"}}
```

## Debugging tips {#templates-debugging}

-   Use `{{debug}}` to inspect the available variables.
-   Enable [rendering.strictMode](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:extension-configuration-rendering-strict-mode@main)
    during development to get an exception for missing variables instead of
    empty output.
-   Compiled templates are cached. Flush caches if template changes don't
    show up.
