A practical guide for Terminalfour administrators. This manual assumes you are already comfortable creating and editing Content Types, Content Layouts, and Page Layouts, and that your layouts are using the Handlebars processor.
What you'll learn
- What Handlebars Partials are and when to reach for them
- The three kinds of partial: standard, partial blocks, and inline
- How to define a partial and call it from any layout
- How to pass parameters in to keep partials flexible
- Three hands-on exercises you can complete in your own instance
What is a Partial?
A Handlebars Partial is a reusable fragment of template markup that you can drop into any Page Layout or Content Layout. If you have worked with shared components before, the idea will feel familiar: you write a piece of markup once, give it a name, and then call it wherever you need it.
Partials are registered across your whole publishing environment, so a partial you define once can be reused in layouts for different channels, page layouts, and content layouts. You call a partial by referencing its name in an expression that starts with an angle bracket:
{{> metaTags}}
Why use Partials?
Without partials, keeping templates consistent across a large site becomes a maintenance chore. Imagine the same block of markup — a card component, a meta tag block, a footer disclaimer — copied across a dozen layouts. Fixing a bug or updating that structure then means editing every layout by hand, and it is easy to miss one.
Partials give you a single source of truth for any repeated markup:
- Less duplication: write a fragment once and reuse it everywhere.
- Easier maintenance: update the partial in one place, and every layout that calls it benefits at the next publish.
- Cleaner layouts: large repeated blocks move out of the parent layout, leaving it focused on its own structure.
- Consistency: because every layout draws from the same partial, the output is identical wherever it appears.
Good candidates for partials include social media meta tag blocks, reusable card or teaser components, schema.org structured-data snippets, shared navigation markup, and standard analytics includes.
The three types of Partial
Terminalfour supports partials in three forms, each suited to a different need:
- Standard partials — a named, reusable fragment stored as a Handlebars Partial content item and called with
{{> partialName}}. Available across your whole environment. This is the most common type. - Partial blocks — a partial used as a wrapper around content, called with
{{#> partialName}} … {{/partialName}}. The wrapped content is rendered wherever the partial outputs{{> @partial-block}}. - Inline partials — a partial defined directly inside a single layout with
{{#*inline "name"}} … {{/inline}}, for reuse within that layout without registering it globally.
Defining a Partial
Like Custom Helpers, partials are managed as content items stored inside a dedicated section in your site structure.
A note on the current setup. Managing partials today means navigating to a specific section in your site structure, identified by a section ID that you retrieve with a SQL query. We know this isn't ideal — it asks for database access and knowledge of Terminalfour internals for what is really just a templating task. This is a temporary requirement. A dedicated UI for creating and managing partials is planned, and when it ships, every partial you have already created through the current workflow will appear there automatically. Nothing will need to be migrated or recreated. Until then, the steps below walk you through the current process.
Step 1 — Find the partials section
Locate the section where partials are stored by running this query against your Terminalfour database:
SELECT * FROM config_option WHERE config_key='handlebars.partialsSectionId'
This returns the section ID for the section where partials are created and managed. Make a note of it. If you can't run SQL against your instance, contact Client Support and they can provide the section ID for you.
Step 2 — Open the section
Navigate to that section in Site Structure. The quickest way is to open any section, then edit the URL in your browser so it references the section ID from Step 1, for example:
https://your-instance.terminalfour.net/terminalfour/page/section#edit/<YOUR_SECTION_ID>
Step 3 — Create a content item
Inside the partials section, create a new content item. Only one Content Type is enabled here, but if you are asked to choose one, select Handlebars Partials. The content item has two elements:
- Name — this becomes the registered name of the partial and is how you reference it in layouts. A name of
articleCardmeans you call it as{{> articleCard}}. Use camelCase to avoid issues. - Code — the Handlebars and/or markup that makes up the partial.
The status of the content item is ignored for partials, but we recommend saving and approving it to avoid confusion later.
Using a Partial in a layout
Once a partial is defined, calling it in any layout is straightforward:
{{> articleCard}}
The > character is Handlebars' syntax for invoking a partial. At publish time, Terminalfour looks up the partial by name and inlines its output at that point in the template. You can call the same partial as many times as you like within a single layout:
<div class="featured">
{{> articleCard}}
</div>
<div class="listing">
{{> articleCard}}
{{> articleCard}}
</div>
Note: a partial can process any Handlebars code, but T4 Tags inside a partial will not be processed. Keep partials Handlebars-only.
Passing parameters into a Partial
Partials are processed in the context in which they are used. So if a partial includes something like {{sectionName}}, it will output a different value depending on where it is called.
By default a partial inherits the full data context of the layout that calls it, so any variable available in the parent layout is available inside the partial too. That works for simple cases, but you'll often want to pass specific values explicitly to make a partial more flexible and self-contained. You do this with hash arguments on the partial call:
{{> articleCard title="Latest News" showImage=true summary=(publish element="Summary") maxWords=80}}
Inside the partial, those values are available as regular Handlebars variables:
{{! articleCard partial }} <div class="card"> {{#if showImage}} <img src="{{imageUrl}}" alt="{{title}}" /> {{/if}} <h3>{{title}}</h3> <p>{{truncate summary maxWords}}</p> </div>
Partial Blocks
Sometimes you want a Partial to act as a wrapper around content rather than just being dropped in on its own – for example, a “card” component that provides a consistent styled container, but where the content inside changes each time it’s used. This is a Partial Block, called with {{#> partialName}} ... {{/partialName}} (note the # before the >). Whatever markup sits between the opening and closing tags is passed into the Partial and rendered wherever the Partial outputs {{> @partial-block}}.
A call in a Content Layout or Page Layout:
{{#> card title="My Block"}}
<p>Some content here</p>
{{/card}}
The card Partial’s own code:
{{!-- @partial-block outputs the content placed between the partial call tags --}}
<div class="card">
{{#if title}}
<h4>{{title}}</h4>
{{/if}}
{{> @partial-block}}
</div>
Key points: the closing tag must match the Partial name; {{> @partial-block}} is where the wrapped content is inserted (if you omit it, the wrapped content is discarded); and you can still pass hash parameters, such as title above, exactly as you would for a normal Partial.
Inline Partials
An inline Partial is defined directly inside a layout with {{#*inline "name"}}, rather than being stored as a separate Handlebars Partial content item. Use this when a reusable fragment is only needed within a single layout and doesn’t warrant a globally registered Partial. Once defined, it is called the same way as any other Partial – {{> name}} – as many times as you need, within that layout only.
{{#*inline "displayMessage"}}
<p>Message to display: {{{message}}}</p>
{{/inline}}
{{>displayMessage message="This is an example of a message"}}
{{>displayMessage message=(publish element="HTML")}}
Best Practices
- Use camelCase for every Partial name (e.g.
articleCard,metaTags) to avoid naming issues. - Keep each Partial focused on one job. A Partial that tries to do too much becomes as hard to maintain as the duplication it was meant to remove.
- Pass values in explicitly with hash parameters rather than relying on inherited context, especially for Partials that will be reused across different Content Types.
- Remember T4 Tags are never processed inside Partial code – only Handlebars expressions.
- Reach for an Inline Partial when the reuse is local to a single layout; reach for a Standard Partial as soon as two or more layouts need the same fragment.
Hands-on Exercise 1: Build and reuse a standard partial
Open the Training: News item Content Type and look at its two Content Layouts – text/html, and text/fulltext. Both layouts independently contain this exact line:
<em><strong>{{dateFormat (dateElement element="Release date") "MMMM d, yyyy"}}</strong></em>
Goal
That is a textbook case for a Standard Partial: one piece of markup, duplicated across two layouts on the same Content Type. While you are at it, you will also make the Partial more flexible by passing in the date style as a parameter, rather than hard-coding a single pattern inside it.
The second argument to the dateFormat Helper accepts either a custom pattern (like "MMMM d, yyyy" above) or one of Terminalfour’s built-in style keywords: full, long, medium, or short. Passing that value in as a parameter means every layout that calls the Partial can choose its own level of detail without touching the Partial’s code.
Steps
- Find your partials section using the SQL query from "Defining a Partial - Step 1" and open it in Site Structure.
- Create a new content item using the Handlebars Partials Content Type.
- Set the Name to
yournameReleaseDate(camelCase — this is the name you'll call). - In the Code element, add the following markup:
-
<em><strong>{{dateFormat date format}}</strong></em>
formatis not hard-coded here – it is a variable that will be supplied by whichever layout calls the Partial. -
- Save and approve the content item.
- Open Training: News item > Content Layouts >
text/html. Replace the date line with the code below (passformat="short"to display an abbreviated date):{{> yournameReleaseDate date=(dateElement element="Release date") format="short"}} - Repeat the same replacement in
text/fulltext, but passingformat="long". - Save each layout, then preview a News item. The full listing and full-text page should show a date like June 19, 2026, while the “latest news” panel shows the shorter 6/19/26.
What to notice
- You have just centralised a piece of formatting logic that previously lived in three places, and made it flexible enough for each layout to request its own date style through a single hash parameter – no duplicate markup, and no duplicate logic either.
- The partial has no idea where its data comes from — you decide that at the call site by passing parameters. That's what makes it reusable.
Hands-on Exercise 2: Wrap content with a partial block
Standard partials drop a fragment in on their own. A partial block instead wraps around content you supply at the call site — ideal for a consistent container whose inner content changes every time.
Goal
Following on from the first exercise both the text/html and text/fulltext layouts on the same News item Content Type wrap their headline link in a heading tag, but at a different level (h3 for the default listing, h2 for the fulltext page). Rather than hard-coding a container around each one, wrap them with a Partial Block so both variants share a single, consistent structure.
Steps
- In your partials section, create another Handlebars Partials content item.
- Set the Name to
yournameNewsCard. - In the Code element, add this markup. The key line is
{{> @partial-block}}, which is where your wrapped content will be inserted:{{!-- newsCard partial block --}} {{#if compact}} <div class="news-card news-card--compact"> {{> @partial-block}} </div> {{else}} <div class="news-card"> {{> @partial-block}} </div> {{/if}} - Save and approve the content item.
- Open
text/htmlon the News item Content Type and wrap the existing headline, date Partial, and teaser output like this, passingcompact=true.
{{#> yournameNewsCard compact="true"}} <h3><a href="{{fulltextURL}}">{{publish element="Headline"}}</a></h3> {{> releaseDate date=(dateElement element="Release date") format="short"}} <p>{{publish element="Teaser" inline-edit="true"}}</p> {{/yournameNewsCard}} - Open
text/fulltextand wrap its elements like so:{{#> yournameNewsCard}} <h2>{{publish element="Headline" inline-edit="true"}}</h2> {{> miguelReleaseDate date=(dateElement element="Release date") format="long"}} <div class="newsimage"> {{{media id=(mediaId element="Image") layout="image/normal"}}} <div class="caption">{{publish element="Image caption" inline-edit="true"}}</div>
</div> <br> <p><strong>{{publish element="Teaser" inline-edit="true"}}</strong></p> {{{publish element="News story" inline-edit="true"}}} {{/yournameNewsCard}} - Save both layouts and preview. Inspect the rendered HTML on a full listing page and on the “latest news” panel – you should see the
news-cardwrapper on both, withnews-card--compactonly on the latter, ready for your CSS to style each variant differently.
Key points for partial blocks
- Open a block partial with
{{#> partialName}}and close it with{{/partialName}}— the closing tag must match the partial name. {{> @partial-block}}inside the partial is where the wrapped content lands. Omit it and the wrapped content is discarded.- You can still pass hash parameters (like
compactabove) on the same call — they behave exactly as they do for a standard partial.
Hands-on Exercise 3: A Direct Edit link that's always right
This exercise shows off the single most important behaviour of partials: a partial is processed in the context in which it is used. Because of this, a partial can output values that depend on the current page — such as a Direct Edit link — and get them right every time, no matter which section it happens to be published in.
The directEditSection helper outputs the path to Direct Edit for the section currently being published. Wrap it in a partial once, call it from your Page Layout, and every page across your site gets the correct "Edit this page" link with zero per-section configuration.
Goal
An editThisPage partial that outputs a Direct Edit link for the current section, called once from a shared Page Layout footer.
Steps
- In your partials section, create a new Handlebars Partials content item.
- Set the Name to
yournameEditThisPage. - In the Code element, add the following. The
directEditSectionhelper does the work — you don't tell it which section to use, because it reads that from the publishing context:<a class="direct-edit" href="{{directEditSection}}">Edit this page</a> - Save and approve the content item.
- Open a Page Layout that uses the Handlebars processor and, in the footer code, call the partial:
{{> editThisPage}} - Assign that Page Layout to two or three different sections (or use one that is already shared across your site).
- Preview or publish pages in each of those sections and hover over the "Edit this page" link. Notice the link target is different in each section — and correct in each case — even though you wrote the partial and the call only once.
Why this works
- The partial contains no hard-coded section —
directEditSectionresolves against whatever section is being published at the moment the partial runs. - Because partials inherit the context of the layout that calls them, the same
{{> editThisPage}}call produces a different, correct link on every page. - This is the real payoff of a single source of truth: one definition, one call, consistent and context-aware output everywhere.
Tip: the same principle applies to anything context-dependent — breadcrumb fragments, canonical URLs, "last updated" stamps, or section-specific metadata. If a value changes per page, a partial can still output it correctly, because it is evaluated where it is used, not where it is defined.
Bonus: Inline partials
When a reusable fragment is only needed within a single layout, you don't have to register a global partial. Define an inline partial right inside the layout with {{#*inline "name"}}, then call it with the usual {{> name}} syntax:
{{#*inline "displayMessage"}}
<p>Message to display: {{{message}}}</p>
{{/inline}}
{{> displayMessage message="This is an example of a message"}}
{{> displayMessage message=(publish element="HTML")}}
An inline partial is only available within the layout (and scope) where it is defined — it is not registered globally like a Handlebars Partial content item.
Quick reference
| You want to… | Use |
|---|---|
| Call a standard partial | {{> partialName}} |
| Pass values into a partial | {{> partialName key="value"}} |
| Wrap content (partial block) | {{#> partialName}} … {{/partialName}} |
| Output wrapped content inside a block partial | {{> @partial-block}} |
| Define a layout-only partial | {{#*inline "name"}} … {{/inline}} |
Things to remember
- Name partials in camelCase.
- Partials process Handlebars only — T4 Tags inside a partial are not processed.
- A partial is evaluated in the context where it is used, so context-dependent helpers (like
directEditSection) output the right value for the current page. - Pass parameters explicitly to keep partials flexible and self-contained.
- Save and approve your partial content items.
- Changes to a partial take effect at the next publish for every layout that calls it.