Headers and footers
Add running headers and footers with page numbers, dates, logos and data, in simple text mode or with your own HTML.
Headers and footers repeat on every page of a PDF. They are configured in output.pdf.header and output.pdf.footer (or stored as defaults on the template), and they come in two flavours: a simple three-slot text mode, and full HTML.
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Draw this header or footer |
html | string | none | HTML mode: the markup to render on every page |
left, center, right | string | none | Simple mode: text for the three slots |
font_size | string | "9px" | Base font size for the header or footer document |
height | string | "15mm" | Height reserved on every page |
Simple mode
Give one or more of left, center and right a line of text. Tokens are replaced per page, and your data is available through the template language:
{
"output": {
"format": "pdf",
"pdf": {
"margin": { "top": "20mm", "right": "16mm", "bottom": "18mm", "left": "16mm" },
"footer": {
"enabled": true,
"left": "{{ company.name }} · Invoice {{ invoice.number }}",
"right": "Page {{page}} of {{pages}}",
"font_size": "8pt",
"height": "12mm"
}
}
}
}| Token | Replaced with |
|---|---|
{{page}} | The current page number |
{{pages}} | The total number of pages |
{{date}} | The date the document was rendered |
{{title}} | The document title |
The {{date}} token uses the renderer's default date format. When the format matters, pass the date in your data and format it yourself, for example {{ invoice.issue_date | format_date("long", "en-GB") }}.
HTML mode
Set html for full control. The markup is a small standalone document that is drawn on every page; spans with particular class names are filled in by the renderer:
{
"header": {
"enabled": true,
"html": "<div style=\"width:100%;padding:0 16mm;font-family:Inter,'Liberation Sans',Arial,sans-serif;display:flex;justify-content:space-between;align-items:center;font-size:8pt;color:#555\"><span>{{ company.name }}</span><span>Page <span class=\"page\"></span> of <span class=\"pages\"></span></span></div>",
"height": "16mm"
}
}The same markup, formatted for reading:
<div style="width:100%;padding:0 16mm;font-family:Inter,'Liberation Sans',Arial,sans-serif;display:flex;justify-content:space-between;align-items:center;font-size:8pt;color:#555">
<span>{{ company.name }}</span>
<span>Page <span class="page"></span> of <span class="pages"></span></span>
</div>| Class | Filled with |
|---|---|
page (alias pageNumber) | The current page number |
pages (alias totalPages) | The total number of pages |
date | The render date |
title | The document title |
url | The document URL, which is most useful for url renders |
Put the class on an empty element: any content inside it is replaced.
How headers and footers are rendered
The header and footer are rendered in an isolated document, separate from your page. That has a few consequences worth knowing:
- Your document's CSS does not apply. Style the header with inline styles.
- Network resources cannot be loaded. Images referenced with
<img src="…">and fonts declared with@font-faceare downloaded and inlined as data URIs for you, up to 2 MB each. You can also inline an image yourself withimage_data_uri(). - The base font size is small. It comes from
font_size(9pxby default), so set it, or set sizes on the elements themselves. - Name a concrete font, not only a generic family. In the header and footer document a bare
font-family: sans-serifresolves to a serif face. Give a family the engine has, with fallbacks, for examplefont-family: "Inter", "Liberation Sans", Arial, sans-serif. - The area spans the full page width, including the page margins. Add horizontal padding that matches your page margins so the header lines up with the body text.
- Background colours print as specified, without extra CSS on your side.
- The template language runs with the same data as the document, and output is autoescaped.
Height and margins
A header is drawn inside the top margin and a footer inside the bottom margin, so the margin has to be large enough to hold it.
- If you don't set
margin.topormargin.bottom, the margin follows theheightof the header or footer. - If you do set them, keep the margin at least as large as
height, plus a few millimetres of breathing room. A margin smaller than the height produces aheader_footer_overlapwarning on the render, and body content can end up underneath the header.
For the example above, a height of 16mm pairs well with a margin.top of 22mm.
Template defaults
Templates store their own header and footer in the editor's Header & footer tab, so most requests don't need to send anything. Options you send with a render request override the template's defaults, which is useful for a "COPY" or "DRAFT" banner in one specific call.
Examples
A footer with page numbers and a company line:
{
"footer": {
"enabled": true,
"html": "<div style=\"width:100%;padding:0 18mm;font-family:Inter,'Liberation Sans',Arial,sans-serif;display:flex;justify-content:space-between;font-size:7.5pt;color:#646a7c\"><span>Example GmbH · VAT DE123456789</span><span>Page <span class=\"page\"></span> of <span class=\"pages\"></span></span></div>",
"height": "14mm"
}
}A letterhead header with a logo, using a data URI so the image is always available:
<div style="width:100%;padding:0 20mm;font-family:Inter,'Liberation Sans',Arial,sans-serif;display:flex;justify-content:space-between;align-items:flex-end;font-size:8pt;color:#333">
<img src="{{ image_data_uri(company.logo_url) }}" alt="" style="height:10mm">
<span>{{ document.type }} {{ document.number }} · {{ document.date | format_date("medium", "en-GB") }}</span>
</div>A centred confidentiality note in simple mode:
{
"header": {
"enabled": true,
"center": "Confidential — prepared for {{ customer.name }}",
"font_size": "8pt",
"height": "12mm"
}
}Planned
- Different headers and footers on the first page, and separate odd and even page variants
- A visual header and footer builder in the editor
- Running section titles, which repeat the current section's heading in the header, as part of the pagination toolkit
Template language
Jinja syntax, autoescaping, built-in filters and every custom filter for money, dates, QR codes, barcodes, charts and layout, with sandbox limits.
Pagination basics
Control page breaks, keep blocks together, repeat table headers and fix the usual pagination problems in HTML to PDF output.