Join the waitlist

How to repeat table headers on every page in a Chrome PDF

You generate a PDF from HTML with Puppeteer or Playwright, and a long table spills onto page two. The header row is gone, a row is sliced in half at the page edge, and your users are counting columns to work out what they're looking at.

Chrome can handle both problems. It just needs the right markup and CSS.

1. Use a real <thead>

Chrome repeats a table's header group on each printed page, but only if it is a header group. A first row of <td>s styled bold doesn't count: it prints once, on page one. A <tfoot> repeats at the bottom of every page the same way.

<table class="report">
  <thead>
    <tr><th>Date</th><th>Description</th><th>Amount</th></tr>
  </thead>
  <tbody>
    <tr><td>2026-10-01</td><td>Consulting</td><td>$1,200.00</td></tr>
    
  </tbody>
</table>

2. Don't override its display

Resets and frameworks sometimes set display: block on table parts, which turns off the repeat. Make sure the header keeps its table role:

thead { display: table-header-group; }
tfoot { display: table-footer-group; }

3. Stop rows splitting across pages

Short rows usually fit, but a row with several lines of content will happily break across the page edge. Tell Chrome not to:

tr, td, th { break-inside: avoid; }

Older guides use page-break-inside: avoid. Chrome still accepts it as an alias, but break-inside is the current property.

4. Print it

// Playwright
await page.setContent(html, { waitUntil: 'networkidle' });
await page.pdf({ path: 'report.pdf', format: 'A4', printBackground: true,
                 margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' } });

Where this stops working

The header repeats, but Chrome still can't do running page headers with the document's own content, "page 3 of 12" inside your layout, or a table of contents that knows which page each section landed on. Those need CSS paged media (@page margin boxes, counter(pages), target-counter()), which Chrome doesn't implement on its own. The next posts cover the workarounds.


I'm building Galley PDF, an HTML-to-PDF API that handles this kind of print layout for you. If PDFs are a pain in your stack, join the waitlist.