Convert an HTML table to PDF without cut-off columns
Practical CSS for wide, long and dense tables, from landscape pages to repeating headers.
Tables are where HTML to PDF conversion goes wrong most often. On screen a table can scroll sideways or stretch as far as it likes; on paper it has a fixed width and has to break across pages. These techniques handle wide tables, long tables and everything in between.
Step 1: give the table the page width
table { width: 100%; border-collapse: collapse; }
th, td { padding: 6px 8px; border-bottom: 1px solid #ddd; text-align: left; }A table with a fixed pixel width wider than the page makes Chromium shrink the whole page to fit, so all your text gets smaller. A table wrapped in a container with overflow-x: auto is worse: the columns beyond the edge are simply missing from the PDF. We measured both in a 12-column table case study. Let the table fill the page instead.
Step 2: make wide tables fit
Try these in order, from least to most intrusive:
- Landscape orientation. On A4 this widens the printable area from about 190 mm to 277 mm with the default 10 mm margins.
- Smaller margins. Dropping from 10 mm to 5 mm on each side gives another 10 mm.
- Smaller type and tighter cells for print only:
@media print { table { font-size: 8.5pt; } th, td { padding: 3px 5px; } } - Let long text wrap. URLs, IDs and email addresses don’t wrap by default and can force a column wide:
td { overflow-wrap: anywhere; } - Fixed layout so columns share space predictably instead of growing with their longest cell:
table { table-layout: fixed; } col.date { width: 14%; } col.description { width: 46%; } - Legal paper. It’s the same width as Letter but taller, so it helps long tables more than wide ones.
If a table genuinely has 20 columns, consider splitting it into two tables with the key column repeated, or rotating the data so rows become columns.
Step 3: repeat headers on every page
Chromium, which renders your PDF, repeats <thead> at the top of each page a table continues onto, and <tfoot> at the bottom. Use real header markup rather than a styled first row:
<table>
<thead>
<tr><th>Order</th><th>Customer</th><th>Date</th><th>Total</th></tr>
</thead>
<tbody>
<tr><td>1001</td><td>A. Patel</td><td>2 Oct 2026</td><td>£84.00</td></tr>
<!-- … hundreds more rows … -->
</tbody>
</table>Step 4: keep rows in one piece
tr { break-inside: avoid; }This stops a row with wrapped text from being sliced through the middle. A single row taller than a page still has to split.
Readable printed tables
- Zebra stripes help readers follow a row across the page. They’re backgrounds on table rows, so they print with Print backgrounds on or off:
tbody tr:nth-child(even) { background: #f3f5f1; } - Right-align numbers and use tabular figures so digits line up:
td.num { text-align: right; font-variant-numeric: tabular-nums; } - Put units in the header (“Total (£)”) rather than every cell to save width.
Very long tables
PDFs are limited to 100 pages. A dense table at 8.5pt fits roughly 50–60 rows per A4 page, so very large exports may need splitting by month, region or customer.
More on breaks: CSS page breaks for PDF.