Guides / Common recipes
Common recipes
Short, copy-paste patterns for the things most documents need.
Line items and totals
Drive a table from an array with {{#each}}. Compute the totals in your data, not the
template, so the arithmetic stays in your code where you can test it.
<table>
<thead>
<tr><th>Item</th><th>Qty</th><th>Amount</th></tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{description}}</td>
<td>{{qty}}</td>
<td>{{amount}}</td>
</tr>
{{/each}}
</tbody>
</table>
<p class="total">Total: {{total}}</p>Use {{@index}}, {{@first}}, and {{@last}} inside the loop for numbering or to drop the
border on the last row.
Conditional sections
Show a block only when data is present, with an optional fallback.
{{#if discount}}
<tr><td>Discount</td><td>-{{discount}}</td></tr>
{{/if}}
{{#unless paid}}
<p class="stamp">UNPAID</p>
{{/unless}}
{{#if shippingAddress}}
{{#with shippingAddress}}<p>{{line1}}, {{city}}</p>{{/with}}
{{else}}
<p>Collect in store.</p>
{{/if}}A variable used only inside {{#if}}/{{#unless}} is treated as optional, so omitting it does
not cause invalid_data.
Multi-page documents
Content flows across pages automatically. Control the breaks with CSS:
.statement + .statement { break-before: page; } /* one statement per page */
tr { break-inside: avoid; } /* keep rows intact */
h2 { break-after: avoid; } /* keep a heading with its body */Put repeating column headers in a <thead>; Chromium repeats it at the top of each page the
table spans. See Page setup for sizing and breaks in detail.
Formatting
There are no formatting helpers in templates (no currency, no date). Format values in your
code before you send them, which keeps locale, currency symbols, and rounding under your
control.
const data = {
total: new Intl.NumberFormat('en-IE', { style: 'currency', currency: 'EUR' }).format(1488),
date: new Intl.DateTimeFormat('en-GB', { dateStyle: 'long' }).format(new Date()),
};
// → total: "€1,488.00", date: "18 June 2026"Then reference the ready-made strings: {{total}}, {{date}}.
Logos and signatures
Embed images as data: URIs so the render never depends on an external host (the most reliable
option for fidelity):
<img class="logo" src="data:image/png;base64,{{logoBase64}}" alt="" />You can pass the base64 string in your data, or hard-code a fixed brand logo directly in the
template. External https:// images also work, subject to the
asset rules.
A repeating footer
Page margins are zero, so pin a footer with position: fixed and it repeats on every page.
.footer {
position: fixed;
bottom: 8mm;
left: 18mm;
right: 18mm;
color: #8a9a94;
font-size: 11px;
}Automatic page numbers ("Page X of Y") are not available today. See the note in Page setup.