Template Partials
Partials are reusable template fragments. Include them with {{> name}} syntax. They live in the _shared/ directory at the notifications root.
Basic partials
Place shared fragments in notifications/_shared/ as .md files:
notifications/
_shared/
email-header.md
email-footer.md
slack-footer.md
transactional/
order-shipped/
email.md
slack.md
Include a partial by name (without the .md extension):
{{> email-header}}
# Your order has shipped
Body content here.
{{> email-footer}}{{> email-header}} loads _shared/email-header.md and inserts its content inline. The partial can contain any valid template syntax -- directives, expressions, images, buttons.
If a partial is not found, the {{> name}} tag is left as-is in the output.
Parameterized partials
Pass named parameters to make partials reusable across different data contexts:
{{> product-card name=item.name price=item.price title="Featured"}}Inside the partial, reference parameters with the {{@param}} prefix:
<!-- _shared/product-card.md -->
**{{@name}}** — {{@price | currency "USD"}}
_{{@title}}_Path vs literal parameters
Parameters come in two forms:
| Form | Syntax | Behavior |
|---|---|---|
| Path | name=item.name |
{{@name}} becomes {{item.name}} -- resolved at compile time from the data context |
| Literal | title="Featured" |
{{@title}} becomes the string Featured directly |
Path parameters use bare unquoted values. Literal parameters use double or single quotes.
{{> card
name=product.name
price=product.price
label="New Arrival"
}}After expansion, the partial content contains standard {{expressions}} that the compiler resolves against the data object.
Pipes with parameters
Parameters work with pipe chains. Inside a partial:
Price: {{@price | currency "USD"}}When called with a path parameter (price=item.cost), this expands to:
Price: {{item.cost | currency "USD"}}
When called with a literal parameter (price="49.99"), this expands to:
Price: {{"49.99" | currency "USD"}}
The pipe chain is preserved in both cases -- only the @ reference is substituted.
Nesting
Partials can include other partials. A product card might include a price tag partial:
<!-- _shared/product-card.md -->
**{{@name}}**
{{> price-tag price=@price}}<!-- _shared/price-tag.md -->
{{@price | currency "USD"}}Norq detects cycles and prevents infinite recursion. If partial a includes b which includes a, the cycle is broken with an HTML comment:
<!-- partial cycle: a -->Missing parameters
If a partial references a parameter that wasn't passed by the caller, the {{@unknown}} tag is left as-is. This is not an error -- it allows partials to have optional parameters.
<!-- _shared/card.md -->
**{{@title}}**
{{@subtitle}}{{> card title=product.name}}Result: {{@subtitle}} remains in the output unchanged.
Example: reusable product card
_shared/product-card.md:
::: callout
**{{@name}}**
{{@price | currency "USD"}}
::: if @description
_{{@description}}_
:::
[View Details]({{@url}}){button.secondary}
:::Caller in email.md:
::: each order.items as item
{{> product-card name=item.name price=item.price url=item.detail_url description=item.summary}}
:::Caller with literal fallback:
{{> product-card name=item.name price=item.price url=item.detail_url description="No description available"}}LSP support
The Norq language server provides completions for partials:
{{>triggers partial name completions -- lists all.mdfiles in_shared/{{@triggers parameter completions inside partial files -- lists known parameter names
See the LSP page for editor setup.