Partials¶
A partial renders a separately-loaded template in place of a {{> key }} tag. Which template
answers a given key is configured by whoever builds the application you're writing templates
for — see Custom Partials if that's you. From a template's point of
view, a partial is resolved once per distinct key per render and its result substituted in place,
as if that other template's text had been written there directly.
Context¶
By default a partial renders against the current context, so a partial used inside {{#each}}
sees the element the loop pushed. A partial key is either:
- a static symbol written literally in the template —
{{> memberInfo }}; or - a parenthesized expression evaluated at render time and coerced to a string —
{{> (which) }}. Whitespace immediately inside the parentheses is optional:{{> (which) }}and{{> ( which ) }}both resolve the same key.
An optional context argument pushes a new scope for the partial, like {{#with}}:
Here the partial renders against the value of spouse instead of the current context.
Failure behavior¶
Partials follow the kBars rule of thumb — mistakes knowable when the template is written fail hard, data-driven mistakes fail soft:
| Situation | Result |
|---|---|
No partial resolver configured for the application, but a {{> … }} tag is present |
hard failure |
| Static symbol key the application doesn't recognize | hard failure |
| Dynamic key that resolves to an unknown key | soft fail: emits nothing |
| Recursion deeper than the application's configured ceiling (default 64) | soft fail: emits nothing |
Partial parameters (from Handlebars) are intentionally not supported.
Inline partials¶
{{#inline name }} … {{/inline}} defines a partial body inline, right in the template:
{{#inline memberInfo}}
- {{ name }} ({{ role }})
{{/inline}}
{{#each member}}{{> memberInfo }}
{{/each}}
The name is a bare identifier, not a quoted string (kBars has no {{#*inline "name"}} form). The
block itself renders nothing; it only registers name so a {{> name }} reference — static or
dynamic — can invoke it, exactly like a loaded partial.
An inline definition is block-scoped: it is visible for the rest of the block it is defined in
(the enclosing template, {{#each}}/{{#if}}/{{#with}} body, or partial body), including
textually before its own definition — the whole block is scanned for definitions before anything
in it renders — and inside any partial invoked from within that block. It goes out of scope once
rendering leaves the enclosing block, so a sibling block cannot see a definition made in another one.
If an inline definition and a loadable partial share a name, the inline definition wins — the loader is never consulted for that name while the inline definition is in scope. This also means an inline partial renders even when no loader is configured at all; the "no loader" hard failure only fires when a static key matches neither an inline definition nor a loader.
Defining the same name twice in one block is last-wins — the later {{#inline}} block is the one
used — and reports a soft failure (KB-5008) each time the enclosing block renders, since it
usually indicates a template bug even though rendering proceeds.
An inline partial's body is subject to the same recursion-depth ceiling as a loaded partial — a self-referential inline partial soft-fails once that ceiling is reached, same as recursion through the loader.
Partial blocks¶
{{#> key }} … {{/>}} (bare close) or {{#> key }} … {{/> key }} (named close) is a partial
block: key resolves exactly like a bare {{> key }} reference — a static symbol, a dynamic
(expr), and an optional trailing context argument all work the same way — but a resolution miss
renders the block's own body as fallback content instead of failing:
If memberInfo resolves (to an in-scope inline definition or a loadable partial), that partial
renders and the fallback is discarded. If it resolves to nothing — no inline definition, an
unregistered static key, an unresolved dynamic key, or no loader configured at all — the
fallback renders instead, silently: no hard failure and no soft-fail event. The fallback is the
author's handling of the miss.
This is the failover half of Handlebars' partial blocks and only that half: kBars has no
{{> @partial-block }} re-entry, so an invoked partial cannot pull the fallback body back in.
Closing forms¶
{{#> memberInfo }} … {{/>}} ← bare close: closes whatever partial block is open, no name check
{{#> memberInfo }} … {{/> memberInfo }} ← named close: the name must equal the open key's literal text
A named close whose name differs from the open key is a hard parse-time authoring error,
KB-4003 (PartialBlockCloseMismatch). A named close only makes sense paired with a symbol
open key — a dynamic open key's literal text (e.g. (which)) can never equal a bare identifier
close name, so pairing a named close with a dynamic open always fails with KB-4003; use the bare
{{/>}} form for a dynamic key.
Context argument and fallback scope¶
A context argument on the open tag ({{#> memberInfo person }}) applies only to the resolved
partial on a hit, exactly like {{> memberInfo person }}. The fallback is inline template content,
not a partial invocation: it renders against the current context, gains no recursion-depth
increment, and adds no frame to the template stack. A self-referential fallback is therefore
ordinary block nesting, not partial recursion.
Where to next¶
- Blocks —
{{#each}}, which composes with a partial to render one partial per loop iteration. - Environment Properties and Scoped Variables — other properties and bindings a partial's context can carry.