How to Convert HTML to PDF

The quickest way to turn a web page into a PDF is the browser's own print dialog: open it, pick the PDF destination and save. To control how that PDF looks, add print CSS with @media print and @page for paper size and margins. For PDFs made automatically, render the page with a headless browser such as Puppeteer or Playwright.

Ways to make a PDF from HTML
MethodRuns whereText selectableBest for
Print dialog, save as PDFAny desktop browserYesOne-off copies of a page
window.print() buttonThe visitor's browserYesInvoices, receipts, tickets
Puppeteer page.pdf()Node.js driving ChromeYesAutomated reports on a server
Playwright page.pdf()A Playwright script driving a browserYesAutomated PDFs inside an existing test setup
html2pdf.jsThe visitor's browserNo, the page becomes an imageQuick client-side downloads
jsPDFThe visitor's browserYes, for text you drawBuilding a PDF from data in code

Updated

Every method on this page ends up asking a browser engine to lay the page out on paper, so good print CSS improves all of them. Build a starting print stylesheet below, then pick the conversion route that matches who presses the button: a person, your page, or a server.

Print CSS builder

@page {
  size: A4 portrait;
  margin: 15mm;
}
@media print {
  body {
    font-size: 12pt;
    color: #000;
    background: #fff;
  }
  nav, header nav, footer, aside, .no-print {
    display: none !important;
  }
  table, figure, pre, img, blockquote {
    break-inside: avoid;
  }
  h1, h2, h3 {
    break-after: avoid;
  }
}

Print CSS reference

Rules and properties that shape printed pages
CSSValuesUse
@media print { }Any rulesStyles that apply only when printing or saving to PDF
@page { size }A5, A4, A3, B5, B4, letter, legal, ledger or lengths; portrait or landscapePaper size and orientation
@page { margin }LengthsMargins of every page
@page :firstPseudo-classDifferent margins on the first page
break-insideauto, avoid, avoid-page, avoid-columnKeep a block on one page
break-before / break-afterauto, avoid, page, left, rightForce or prevent a break at a block
print-color-adjusteconomy, exactWhether the browser may drop colours and backgrounds

Copyable print examples

A print or save as PDF button

window.print() opens the print dialog and blocks the page until it closes. The class keeps the button itself off the paper.

<button type="button" class="no-print" onclick="window.print()">Print or save as PDF</button>

<style>
  @media print { .no-print { display: none } }
</style>

Invoice layout that starts each invoice on a new page

break-after: page after each invoice gives one invoice per sheet when several are printed together.

@page { size: A4; margin: 18mm 15mm; }
@page :first { margin-top: 25mm; }

@media print {
  .invoice { break-after: page; }
  .invoice:last-child { break-after: auto; }
  .invoice table { width: 100%; border-collapse: collapse; }
  .invoice tr { break-inside: avoid; }
}

Prepare the page just before printing

beforeprint and afterprint fire around the dialog, which is useful for expanding collapsed sections.

window.addEventListener("beforeprint", () => {
  document.querySelectorAll("details").forEach((d) => d.setAttribute("open", ""));
});
window.addEventListener("afterprint", () => {
  console.log("Print dialog closed");
});

Server-side PDF with Puppeteer

preferCSSPageSize lets your @page size win over the format option; printBackground keeps backgrounds.

import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://example.com/invoice/42", { waitUntil: "networkidle0" });
await page.pdf({
  path: "invoice-42.pdf",
  printBackground: true,
  preferCSSPageSize: true,
});
await browser.close();

Print CSS is the foundation

A @media print block lets you restyle the page for paper without touching the screen design. Hide what makes no sense on paper, widen the content column, and set a readable font size.

The @page rule controls the page box itself: size, margins and orientation, with :first, :left and :right to treat specific pages differently. MDN lists @page as Baseline newly available since December 2024, with some parts still varying between browsers.

When to render on a server

If PDFs must be produced without a person, such as a nightly report or an emailed invoice, run a headless browser. Puppeteer's page.pdf() prints with the print media type, takes options such as format, margin and printBackground, and can save straight to a file path.

Server rendering gives the same result every time because you control the browser version and fonts. It also means running and securing that browser, so only take it on when a print button is not enough.

How it works

  1. Choose a paper size, orientation and margin for the @page rule.
  2. Tick the extras you need: hide navigation, keep blocks together, print link addresses, keep background colours.
  3. Copy the CSS into your stylesheet; it only applies when printing.
  4. Open the print preview in your browser and choose the PDF destination to check the result.

Tips

Frequently asked questions

How do I save a web page as a PDF without any tools?

Open the browser's print dialog from its menu or keyboard shortcut, then choose the PDF option in the destination or printer list. Its exact name depends on the browser and operating system.

How do I add a Download PDF button to my page?

The simplest honest version is a button that calls window.print(), which opens the same dialog, where the visitor can save as PDF. It needs no library, keeps text selectable and uses your print CSS.

How do I stop a table splitting across two pages?

Add break-inside: avoid to the table, or to its rows if the table is long. The older page-break-inside: avoid is treated as an alias, so it still works in older stylesheets.

Can I set the paper size from CSS?

Yes. @page { size: A4 portrait; margin: 15mm; } sets the size and margins of the page box. Puppeteer only uses it when preferCSSPageSize is true; otherwise its own format option, Letter by default, decides.

Why does html2pdf.js produce blurry or huge PDFs?

Its README explains that it renders the content into an image and places that image in the PDF, so the text is not selectable or searchable and files get large. Use printing or a headless browser when the text matters.

Related: Print HTML tool, HTML viewer, CSS print styles, HTML table borders, HTML and CSS cheat sheet.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap