DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk7 min

How to Convert HTML to PDF in JavaScript

Choose browser printing for user-controlled saves, html2pdf.js for simple browser downloads, or Puppeteer for Node.js PDF generation. See code, limitations, and troubleshooting.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The right way to convert HTML to PDF in JavaScript depends on where the code runs. For a user-initiated save, use the browser’s print flow and print CSS. For a browser-side download of an element, html2pdf.js is a convenience option, but it creates image-based PDFs. For server-side rendering in Node.js, use Puppeteer’s page.pdf(). Use pdf-lib when you need to create or edit PDF objects directly, not to render arbitrary HTML and CSS.

Choose an approach based on runtime and output

Approach Where it runs Use it for Main trade-off
Browser print flow In the user’s browser Letting users print or save the page through the browser’s print controls The browser controls the final dialog and settings; you need a print layout that works in supported browsers.
html2pdf.js Browser only A simple client-side PDF download of an element or page It renders content as an image, so PDF text is not selectable or searchable; reflow and canvas-size limits can affect results.
Puppeteer page.pdf() Node.js-controlled browser workflow Automated or server-side PDF generation from a rendered page PDF output uses print media by default, so print styling, assets, colors, and browser lifecycle need attention.
pdf-lib Browser, Node.js, Deno, React Native, and other supported JavaScript runtimes Creating or modifying PDF documents, pages, forms, text, and images It is not a browser layout engine for converting arbitrary HTML/CSS.

These tools solve different problems; choose by where HTML is rendered and whether you need browser layout or direct PDF editing. The html2pdf.js project documents its browser-only workflow and dependencies in its README. Puppeteer documents PDF behavior in its Page.pdf() API reference and PDF generation guide. pdf-lib describes its creation and modification capabilities in its project documentation.

Let users print or save the rendered page

If the PDF should reflect a page the user is already viewing, call window.print() in response to an explicit user action. The browser presents its print interface, where the user chooses a printer or a PDF destination and controls available print settings. Add a print stylesheet to remove screen-only controls and tune page layout.

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

<style>
@media print {
  .site-nav,
  .print-button,
  .screen-only {
    display: none !important;
  }

  main {
    width: auto;
    margin: 0;
  }

  h1, h2, h3 {
    break-after: avoid;
  }

  .new-page {
    break-before: page;
  }
}
</style>

Use semantic, print-friendly HTML and check the page in each browser you support. Page breaks, margins, backgrounds, and available dialog options may differ by browser and user settings. Keep essential content visible in print rather than relying on navigation or interactive controls.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Download a browser-side PDF with html2pdf.js

html2pdf.js is a browser-side pipeline built on html2canvas and jsPDF. Install it with npm using npm install --save html2pdf.js, then pass the target element to the library. Its project documentation says it must run in a browser, not Node.js.

import html2pdf from 'html2pdf.js';

const element = document.getElementById('element-to-print');
if (!element) {
  throw new Error('Could not find #element-to-print');
}

html2pdf().from(element).save('page.pdf');

The short pattern documented by the project is html2pdf(element); the chained form above makes the source element and save action explicit. Make sure the element exists and that its fonts and images have loaded before starting the capture. Try the result with representative content, including long pages and complex styling, in the browser where the feature will run.

Understand the image-based output

The project’s documented renderer creates an image and places it in the PDF. As a result, the text is not selectable or searchable like text in a document rendered by a browser’s print-to-PDF engine. The renderer may resize or reflow content to fit pages, and very large canvas dimensions can exceed browser limits and yield blank output. The README also identifies HTML rendering and cloned-node/CSS issues as known limitations. Check web fonts, images, page breaks, and styling with your actual page before relying on the output.

Generate a PDF from Node.js with Puppeteer

Puppeteer drives a browser and exposes page.pdf() to generate a PDF from the loaded page. Install Puppeteer in your Node.js project, then launch a browser, navigate to the target, generate the file, and close the browser. The following complete example closes the browser even if navigation or PDF generation fails:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

async function savePageAsPdf(url, outputPath = 'output.pdf') {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'networkidle2' });
    await page.pdf({ path: outputPath });
  } finally {
    await browser.close();
  }
}

savePageAsPdf('https://example.com', 'output.pdf').catch((error) => {
  console.error('PDF generation failed:', error);
  process.exitCode = 1;
});

This follows the lifecycle in Puppeteer’s PDF generation guide. Its documented page.pdf() behavior uses print CSS media by default and waits for fonts by default. That makes print styles—not necessarily the page’s on-screen appearance—the starting point for the PDF.

Choose print or screen media deliberately

If you want the page styled for screen rather than print, emulate screen media before generating the PDF:

await page.emulateMediaType('screen');
await page.pdf({ path: 'output.pdf' });

The API documentation also notes that printing modifies colors by default. If exact color rendering is important, use the CSS print-color adjustment property it documents, such as -webkit-print-color-adjust: exact, and verify the output in your target environment. Background graphics and other print settings can affect the final appearance.

Wait for the content your page needs

The guide’s example navigates with waitUntil: 'networkidle2'; that is a navigation condition, not proof that every application-specific task or delayed asset is finished. If your page renders data asynchronously, wait for a selector or application-ready signal before calling page.pdf(). Confirm that images and fonts are available, and consider pages that load content only after scrolling or interaction. Puppeteer’s documented default font waiting helps with fonts, but does not replace checks for the rest of your page’s readiness conditions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use pdf-lib to build or edit PDF documents

Choose pdf-lib when the output is assembled from PDF primitives or when you need to modify an existing PDF: add pages, draw text or images, embed fonts, fill forms, or split and merge documents. The project documents support across several JavaScript environments and examples using PDFDocument.create() and page drawing methods.

It is not a drop-in replacement for Chromium when the input is a complex HTML/CSS layout. If visual fidelity to a webpage matters, render the page with a browser workflow such as Puppeteer; if you need precise control over PDF objects, work directly with a PDF library such as pdf-lib.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For a one-request screenshot or PDF of a URL, ScreenshotNeo provides a website screenshot API and MCP server. Its GET endpoint can return an image or PDF; the PDF example is below. See the API documentation for options and authentication.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.pdf
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; the response reports the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 shots per month with no card required; paid plans start at $5 for 3,000 shots.

Sign up free for 1,000 screenshots a month, with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot common HTML-to-PDF problems

  • html2pdf.js fails in Node.js: it is documented as browser-only. Use Puppeteer for a Node.js-controlled browser workflow instead.
  • The PDF text cannot be selected or searched: html2pdf.js places a rendered image in the PDF. Use browser printing or Puppeteer’s browser-generated PDF when text output matters.
  • The html2pdf.js output is blank or clipped: oversized canvas dimensions can hit browser limits. Test a smaller or shorter capture and review the project’s documented HTML and cloned-node/CSS limitations.
  • Puppeteer output uses the wrong layout: page.pdf() defaults to print media. Add or fix @media print styles, or call page.emulateMediaType('screen') before PDF generation if screen styling is intended.
  • Fonts or images are missing: ensure assets are reachable and the application has finished rendering before generating the PDF. Puppeteer waits for fonts by default, but delayed data or images may need an application-specific readiness check.
  • Colors differ in Puppeteer output: PDF printing adjusts colors by default. Use the documented print-color adjustment CSS when exact colors are required, then verify the result.
  • The browser remains open after an error: put browser.close() in a finally block so navigation or PDF failures do not skip cleanup.

Frequently asked questions

Can browser JavaScript save a PDF without opening a print dialog?

The print-flow approach hands the final destination and settings to the browser’s print interface. For a direct browser-side element download, html2pdf.js provides a download workflow, with the image-based output limitations described above.

Should I use pdf-lib or Puppeteer for an HTML invoice?

Use Puppeteer if the invoice already exists as HTML/CSS and you want browser layout rendering. Use pdf-lib if you are assembling the document from PDF-level text, images, forms, or pages rather than rendering an HTML layout.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5× more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.