Headers, footers and page numbers in HTML-to-PDF
, 5 min read
Running headers, “Page 3 of 12” footers and repeated table headers are the details that make a generated report look finished. Chromium supports all of them, with a few quirks worth knowing.
Header and footer templates
Pass headerHtml and footerHtml. Chromium renders them in a separate context on every page and fills in these classes:
pageNumber | Current page |
totalPages | Total pages |
date | Print date |
title | The document’s <title> |
url | Document URL |
{
"html": "<h1>Quarterly report</h1>…",
"format": "A4",
"margin": {
"top": "24mm",
"bottom": "20mm",
"left": "16mm",
"right": "16mm"
},
"headerHtml": "<div style=\"font-size:9px;width:100%;padding:0 16mm;display:flex;justify-content:space-between\"><span>Example Ltd</span><span class=\"title\"></span></div>",
"footerHtml": "<div style=\"font-size:9px;width:100%;padding:0 16mm;text-align:right\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>"
}The three quirks
- Set a font size. Header and footer text defaults to a tiny size and ignores your page’s stylesheet. Put styles inline, including
font-sizeandfont-family. - Make room with margins. Headers and footers draw inside the page margin. With a zero top margin the header is invisible. Around 20–25 mm top and bottom fits one line comfortably.
- Images must be inline. The header context can’t fetch URLs. Use a
data:URI or an inline<svg>for a logo.
Tables across pages
Chromium repeats <thead> on every page when a table breaks. Keep rows whole and avoid orphaned headings:
tr, .card { break-inside: avoid; }
h2, h3 { break-after: avoid; }
.page-break { break-before: page; }
thead { display: table-header-group; }
tfoot { display: table-footer-group; }Different first page
Chromium applies the same header and footer to every page. For a cover page without them, render the cover and the body as two requests and merge them with a library such as pdf-lib, or design the header so it reads well on the cover too.
The report template uses all of the above. Its header and footer are attached when you render the built-in report id.