Pagination basics
Control page breaks, keep blocks together, repeat table headers and fix the usual pagination problems in HTML to PDF output.
A PDF is your HTML poured into fixed-size pages. Chromium decides where the content breaks, and CSS fragmentation properties let you steer those decisions. This page collects the rules that matter for documents, and the fixes for the problems that come up most often.
The page box comes from the PDF options: paper, orientation and margin, or from your CSS @page rule when prefer_css_page_size is on.
Force a page break
Break before or after an element with CSS:
.chapter { break-before: page; }
.cover { break-after: page; }Or insert a break from the template, which is easier inside loops:
{% for certificate in certificates %}
<section class="certificate">…</section>
{% if not loop.last %}{{ page_break() }}{% endif %}
{% endfor %}Note the loop.last check: a break after the final element produces an empty last page.
Keep content together
break-inside: avoid moves an element to the next page instead of splitting it:
.totals,
.signature-block,
figure,
tr {
break-inside: avoid;
}An element taller than one page will still be split: there is nowhere else to put it.
Keep a heading with its content
break-after: avoid asks for no break directly after an element:
h2, h3 { break-after: avoid; }The most reliable approach is to wrap the heading and the first block that must stay with it:
<div style="break-inside: avoid">
<h2>Payment details</h2>
<p>Please transfer the total to the account below within 30 days.</p>
</div>Tables
Long tables are the main source of pagination problems. Three rules cover most of it:
thead { display: table-header-group; }
tfoot { display: table-footer-group; }
tr { break-inside: avoid; }theadrepeats the header row at the top of every page the table spans. Put the header cells in a real<thead>element, not in the first<tbody>row.- A
tfootgroup repeats at the bottom of every page, so keep grand totals in a block after the table if they should appear only once. tr { break-inside: avoid; }keeps a row's cells on one page. Rows with a lot of text can still break if a single row is taller than the page.
Orphans and widows
Stop single lines being left behind at the bottom or top of a page:
p { orphans: 3; widows: 3; }Page size in CSS
By default the paper, orientation and margin options define the page. With prefer_css_page_size: true, the size from your CSS wins, which also allows different sizes within one document using named pages:
@page { size: A4; }
@page wide { size: A4 landscape; }
.appendix-table { page: wide; }Keep setting margins through the margin option, so that headers and footers and your margins stay in sync.
Single-page output
single_page: true produces one page as tall as the content, with the paper width you set. It is the usual choice for receipts on narrow paper and for continuous documents that will be read on screen:
{ "paper": { "width": "80mm", "height": "200mm" }, "single_page": true }Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Table rows split across pages | Rows may break by default | tr { break-inside: avoid; } |
| Header row only on the first page | Header cells are in tbody, or display was overridden | Use <thead> with display: table-header-group |
| Empty page at the end | A break after the last element, or a full-height element | Skip the break for the last item, avoid height: 100vh and fixed full-page heights |
| Heading alone at the bottom of a page | No keep-with-next rule | break-after: avoid, or wrap heading and first paragraph in a break-inside: avoid container |
| Body text hidden behind the header or footer | Margin smaller than the header or footer height | Increase margin.top or margin.bottom; check the render's warnings |
| Background colours or images missing | Backgrounds aren't printed | Set print_background: true and print-color-adjust: exact on the element |
| The PDF looks different from the browser | Print styles are applied | Check your @media print rules, or render with emulate_media: "screen" |
| Wrong or fallback fonts | The font isn't bundled with the engine, or its file couldn't be loaded | Use the engine's bundled fonts, or declare @font-face in the head with a reachable source. The browser falls back without a warning, but a font file that couldn't be loaded shows up as an asset_failed warning |
| Content cut off on the right | Fixed widths wider than the printable area | Printable width is the paper width minus both margins, for example 180 mm on A4 with 15 mm margins. Use percentages and box-sizing: border-box. |
| Flex or grid sections break oddly | Fragmentation of flex and grid containers is limited | Use block layout or tables for long, paginated content |
| Unexpectedly many pages | Long data, oversized images or forced breaks | Check the render's pages count; a PDF over your plan's page limit fails with page_limit_exceeded |
Page numbers
Page numbers belong in the header or footer, where the renderer fills in the current and total page numbers. See Headers and footers.
Pagination toolkit
Renders of code and Markdown templates, and of HTML or Markdown you send, load a small pagination stylesheet that covers the same ground with less CSS. Pages rendered from a URL don't get it.
Print defaults. Table header and footer groups repeat on every page. Table rows, images, SVGs and figures aren't split. Paragraphs, list items and quotes keep at least three lines at the bottom and top of a page, and headings stay with what follows them. The defaults sit in a CSS cascade layer, so any rule of your own overrides them.
Utility classes. Add them to elements in your template:
| Class | Effect |
|---|---|
.dda-keep-together | Don't split the element across pages |
.dda-keep-with-next | No page break directly after the element |
.dda-page-break-before, .dda-page-break-after | Start a new page before or after the element |
.dda-avoid-row-split, .dda-allow-row-split | On a table or a row: keep rows on one page, or let them break |
.dda-repeat-header, .dda-no-repeat-header | On a table: repeat the header row on every page, or print it once |
.dda-orphans-widows | Keep at least three lines at the bottom and top of a page |
.dda-print-only, .dda-screen-only | Show the element only in print, as in PDFs, or only on screen |
.dda-fill-page | Fill the remaining page height, for example to push a signature block to the bottom |
Pagination check. The editor's PDF preview flags table rows and images split across pages, tables that continue without their header, table footers such as totals that print on every page, headings at the bottom of a page, elements wider than the printable area, unbreakable blocks taller than a page, and blank or nearly blank last pages. Most findings come with a one-click fix that adds CSS to the template's head.
Still planned:
.dda-running-title, which repeats the current section's title in the header- an optional paged-media mode for features Chromium lacks, such as running elements, tables of contents with page references, and footnotes