Convert an HTML table to PDF without cut-off columns

Practical CSS for wide, long and dense tables, from landscape pages to repeating headers.

Updated · 5 min read

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:

  1. Landscape orientation. On A4 this widens the printable area from about 190 mm to 277 mm with the default 10 mm margins.
  2. Smaller margins. Dropping from 10 mm to 5 mm on each side gives another 10 mm.
  3. Smaller type and tighter cells for print only:
    @media print {
      table { font-size: 8.5pt; }
      th, td { padding: 3px 5px; }
    }
  4. Let long text wrap. URLs, IDs and email addresses don’t wrap by default and can force a column wide:
    td { overflow-wrap: anywhere; }
  5. 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%; }
  6. 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.