SyntaxdocSyntaxdoc
Blog

Handling Page Breaks in PDF Generation

Master the art of page breaks in HTML to PDF conversion. Learn how to control where content splits and keep important elements together.

Handling Page Breaks in PDF Generation

One of the most challenging aspects of HTML to PDF conversion is controlling page breaks. Poor page break handling can result in:

  • Tables split awkwardly mid-row
  • Headers separated from their content
  • Broken layouts and orphaned text
  • Poor readability

Let's master page breaks once and for all.

CSS Page Break Properties

CSS provides several properties for controlling page breaks:

/* Force a page break before an element */
.new-chapter {
  page-break-before: always;
}

/* Prevent page breaks inside an element */
.keep-together {
  page-break-inside: avoid;
}

/* Force a page break after an element */
.section-end {
  page-break-after: always;
}

Modern CSS (Better Browser Support)

The newer break- properties are recommended:

.new-chapter {
  break-before: page;
}

.keep-together {
  break-inside: avoid;
}

.section-end {
  break-after: page;
}

SyntaxDoc supports both the legacy page-break-* and modern break-* properties.

Common Scenarios

1. Keep Tables Together

Never split a table header from its content:

table {
  break-inside: avoid;
}

/* For large tables that must span pages */
table.large {
  break-inside: auto;
}

thead {
  display: table-header-group; /* Repeat on each page */
}

tr {
  break-inside: avoid;
  break-after: auto;
}

2. Keep Headings with Content

Prevent headings from appearing alone at the bottom of a page:

h1, h2, h3, h4, h5, h6 {
  break-after: avoid;
  break-inside: avoid;
}

/* Also keep the first paragraph with the heading */
h1 + p, h2 + p, h3 + p {
  break-before: avoid;
}

3. Invoice Line Items

Keep invoice items properly grouped:

.invoice-items table {
  break-inside: auto;
}

.invoice-items tr {
  break-inside: avoid;
}

.invoice-totals {
  break-inside: avoid;
  break-before: avoid; /* Keep with last item */
}

4. Multi-Column Layouts

Handle columns carefully:

.column {
  break-inside: avoid;
  page-break-inside: avoid;
}

.column-break {
  break-after: column;
}

Advanced Techniques

Widows and Orphans

Control how many lines must appear at page breaks:

p {
  orphans: 3; /* Minimum lines at bottom of page */
  widows: 3;  /* Minimum lines at top of page */
}

Orphan: The first line of a paragraph appearing alone at the bottom of a page
Widow: The last line of a paragraph appearing alone at the top of a page

Smart Page Margins

Add extra space before page breaks:

@page {
  margin: 20mm;
  
  @top-center {
    content: "Document Title";
  }
}

/* First page different */
@page :first {
  margin-top: 50mm;
}

Content-Aware Breaks

Use data attributes to control breaks dynamically:

<div class="section" data-keep-together="true">
  <!-- Content that must stay together -->
</div>
[data-keep-together="true"] {
  break-inside: avoid;
}

The SyntaxDoc Advantage

SyntaxDoc includes intelligent page break handling that goes beyond standard CSS:

Automatic Table Splitting

{
  "options": {
    "smartPageBreaks": true,
    "tableHandling": "auto-split"
  }
}

This automatically:

  • Repeats table headers on new pages
  • Prevents single rows from being orphaned
  • Adds continuation markers
  • Maintains table styling across breaks

Smart Content Flow

{
  "options": {
    "smartPageBreaks": true,
    "orphanControl": "strict"
  }
}

Features:

  • Detects related content (headings + paragraphs)
  • Prevents awkward splits
  • Optimizes whitespace
  • Maintains visual hierarchy

Testing Your Page Breaks

Always test with various content lengths:

// Test with different amounts of content
const testCases = [
  { items: 5, description: "Single page" },
  { items: 25, description: "Multi-page" },
  { items: 100, description: "Large document" },
];

for (const test of testCases) {
  const html = generateInvoice({ itemCount: test.items });
  const pdf = await generatePDF(html);
  console.log(`${test.description}: ${pdf.pages} pages`);
}

Best Practices Checklist

✅ Do

  • Test with various content lengths
  • Use break-inside: avoid on critical elements
  • Keep related content together
  • Use appropriate margins
  • Test headers and footers across pages
  • Consider mobile/print preview during development

❌ Don't

  • Force page breaks unnecessarily
  • Use absolute positioning near page boundaries
  • Ignore table headers on continuation pages
  • Forget about widows and orphans
  • Use overly complex nested layouts

Common Issues and Solutions

Issue: Table Rows Split Across Pages

Solution:

tr {
  break-inside: avoid;
  page-break-inside: avoid;
}

Issue: Large Images Causing Breaks

Solution:

img {
  max-height: 80vh; /* Prevent images from forcing breaks */
  break-inside: avoid;
}

Issue: Floated Elements Causing Issues

Solution:

/* Clear floats before page breaks */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
  page-break-after: always;
}

Example: Complete Invoice Page Breaks

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      padding: 20mm;
    }
    
    .invoice-header {
      break-inside: avoid;
      break-after: avoid;
    }
    
    .invoice-items table {
      width: 100%;
      break-inside: auto;
    }
    
    .invoice-items tr {
      break-inside: avoid;
    }
    
    .invoice-items thead {
      display: table-header-group;
    }
    
    .invoice-totals {
      break-inside: avoid;
      break-before: avoid;
      margin-top: 2rem;
    }
    
    .invoice-terms {
      break-before: page;
    }
  </style>
</head>
<body>
  <div class="invoice-header">
    <!-- Header content -->
  </div>
  
  <div class="invoice-items">
    <table>
      <thead>
        <tr>
          <th>Item</th>
          <th>Quantity</th>
          <th>Price</th>
        </tr>
      </thead>
      <tbody>
        <!-- Items -->
      </tbody>
    </table>
  </div>
  
  <div class="invoice-totals">
    <!-- Totals -->
  </div>
  
  <div class="invoice-terms">
    <!-- Terms and conditions on new page -->
  </div>
</body>
</html>

Learn More

Start generating PDFs with perfect page breaks using SyntaxDoc's smart algorithms.

On this page