CSS page breaks for HTML to PDF

CSS page breaks for HTML to PDF

CSS page breaks for HTML to PDF: force breaks, keep tables and cards together, avoid orphan headings, and set page size with @page.

These rules work in any Chromium-based renderer. That includes Chrome's "Save as PDF", Puppeteer, Playwright, Gotenberg and html-pdf.com.

Quick answer. Add break-before: page where a new page should start and break-inside: avoid on things that must stay whole, then render:

curl https://html-pdf.com/v1/pdf -H "Authorization: Bearer $HTML_PDF_KEY" -H "Content-Type: application/json" \
  -d '{"html": "<style>.pb{break-before:page}</style><h1>Page 1</h1><h1 class=\"pb\">Page 2</h1>"}' -o out.pdf

Force a new page

This rule starts an element on a fresh page.

.page-break { break-before: page; }
<section>Cover</section>
<section class="page-break">Chapter 1</section>

break-before: page is the modern property. The legacy page-break-before: always still works and is a safe fallback.

.page-break { page-break-before: always; break-before: page; }

Use break-after: page to break after an element instead.

Keep things together

These rules stop content from being split awkwardly across pages. To keep a card, a table row or a figure on one page, use break-inside: avoid.

.card, figure, tr, .totals { break-inside: avoid; page-break-inside: avoid; }

To keep a heading with the paragraph that follows it, avoid a break after the heading.

h2, h3 { break-after: avoid; page-break-after: avoid; }

To avoid lonely lines at the top or bottom of a page, set orphans and widows.

p { orphans: 3; widows: 3; }

Repeat table headers on every page

This makes long tables readable on every page. Chromium repeats <thead> automatically when a table spans pages, as long as you use real table markup.

<table>
  <thead><tr><th>Item</th><th>Qty</th><th>Price</th></tr></thead>
  <tbody>…hundreds of rows…</tbody>
</table>
thead { display: table-header-group; }
tr { break-inside: avoid; }

Page size and margins with @page

This section sets paper size and margins from CSS.

@page { size: A4; margin: 20mm 15mm; }
@page :first { margin-top: 40mm; }

Chromium only uses the CSS size when the renderer is told to prefer it. With html-pdf.com, set prefer_css_page_size.

curl https://html-pdf.com/v1/pdf -H "Authorization: Bearer $HTML_PDF_KEY" \
  -d '{"html": "<style>@page{size:A5;margin:12mm}</style><h1>A5 booklet</h1>", "prefer_css_page_size": true}' -o a5.pdf

Or skip CSS and pass format (A4, Letter, …), landscape and margin in the request. Chromium also supports CSS @page margin boxes (Chrome 131+), which you can use for running headers and footers.

Common pitfalls

These are the most common reasons page breaks don't behave as expected.

Test it in one call

You can check your page breaks in seconds. Paste your HTML into the converter on html-pdf.com or call the API.

You get 100 free pages, then pay from $0.005 per page, and purchased credits never expire. Next: headers, footers and page numbers.

FAQ

How do I force a page break when converting HTML to PDF?

Add break-before: page (or the legacy page-break-before: always) to the element that should start a new page. It works in Chrome, Puppeteer, Playwright, Gotenberg and html-pdf.com.

How do I stop a table row from splitting across pages?

Set tr { break-inside: avoid; }. Use real <thead> markup too, and Chromium repeats the header row on every page.

Why are my page breaks ignored?

Page-break properties only apply to block-level boxes in normal flow, so they're often ignored inside flex or grid containers. Fixed heights and overflow: hidden can also clip content instead of letting it flow onto the next page.

Does the API respect @page size from CSS?

Yes, when you set prefer_css_page_size: true in the request. Otherwise, pass format, landscape and margin as request options.

This page as markdown · text