Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
There is no single “React to PDF” library for every job. Use react-to-print when a user should print a component and choose “Save as PDF”; use html2pdf.js when the conversion must happen in the user’s browser; and use Puppeteer or Playwright when a server or automated worker must produce a repeatable PDF. The key differences are who controls rendering, whether text stays selectable, how closely print CSS is followed, and where the browser runtime is hosted.
Choose the rendering model before choosing a package
“Convert a React component to PDF” describes several different workflows. A print button, an offline browser export and an automated invoice service have different requirements.
| Requirement | Best starting point | Main trade-off |
|---|---|---|
| Let a user print selected React UI and choose a destination such as Save as PDF | react-to-print |
The browser owns the print dialog and settings. The library does not directly download a PDF by itself. |
| Create a PDF from an element in the user’s browser | html2pdf.js |
Convenient and client-side, but it rasterizes the rendered page; text may not remain selectable or searchable and files can be larger. |
| Generate PDFs automatically from rendered HTML | Puppeteer or Playwright | Requires a headless-browser runtime and operational work. PDFs use print CSS media by default. |
For long, data-heavy documents where users need search, copy and accessibility, treat image-based output as a serious limitation. For deterministic delivery—such as emailing an invoice after an order—run a browser automation library in a controlled server or job worker. Browser behavior and package APIs change, so test the exact browsers and versions you support.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Option 1: print a React component with react-to-print
react-to-print prepares the content of a selected component and invokes the native browser print flow. The user still sees print preview and chooses “Save as PDF”; the package does not silently download a PDF without that preview. Its custom print hook can hand the prepared content to another generator if your application needs a different output path.
#1 Best Overall
Install and create a printable component
npm install react-to-print
import { useRef } from "react";
import { useReactToPrint } from "react-to-print";
export default function InvoicePage({ invoice }) {
const printRef = useRef(null);
const printInvoice = useReactToPrint({
contentRef: printRef,
documentTitle: `invoice-${invoice.number}`,
onPrintError: (location, error) => {
console.error(`Print failed during ${location}`, error);
}
});
return (
<>
<button type="button" onClick={printInvoice}>Print / Save PDF</button>
<main ref={printRef} className="invoice">
<h1>Invoice {invoice.number}</h1>
<p>Customer: {invoice.customer}</p>
<ol>
{invoice.items.map((item) => (
<li key={item.id}>{item.description}: {item.total}</li>
))}
</ol>
</main>
</>
);
}
Use the ref on the actual node you want copied into the print document. Print-specific CSS should target that node and its descendants; ancestor styles outside the printed subtree may not be present.
@media print {
body { margin: 0; }
.invoice { color: #000; background: #fff; padding: 12mm; }
.no-print, button { display: none !important; }
.invoice { break-inside: avoid; }
}
What this route can and cannot control
- The user’s browser controls paper size, margins, headers and footers, scaling and destination. JavaScript cannot reliably set those print-dialog choices through
window.print. - Fonts, images and asynchronous data must be ready before printing. Render loading states only after the data has arrived.
- Most modern desktop browsers are supported, but project documentation calls out limitations in mobile WebViews and Firefox for Android. Test every target environment, especially an embedded WebView.
- Because the browser owns the final print operation, this is usually the simplest and most user-friendly choice for an interactive “print this view” button.
Option 2: create a client-side file with html2pdf.js
html2pdf.js converts a webpage or selected element in the browser using html2canvas and jsPDF. It is browser-only; it does not run in Node.js. The DOM is rendered to a canvas and placed into a PDF, so the result can lose selectable/searchable text and may be larger than a PDF generated from real text and vector layout.
Install and export an element
npm install html2pdf.js
import html2pdf from "html2pdf.js";
export async function downloadReceipt(element) {
if (!element) throw new Error("Receipt element is not available");
const options = {
margin: [10, 10, 10, 10],
filename: "receipt.pdf",
image: { type: "jpeg", quality: 0.95 },
html2canvas: {
scale: 2,
useCORS: true,
backgroundColor: "#ffffff"
},
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
pagebreak: { mode: ["css", "legacy"] }
};
await html2pdf().set(options).from(element).save();
}
In a component, attach a ref and call the function from a click handler:
import { useRef } from "react";
import { downloadReceipt } from "./downloadReceipt";
export function Receipt({ order }) {
const receiptRef = useRef(null);
return (
<>
<button onClick={() => downloadReceipt(receiptRef.current)}>
Download PDF
</button>
<article ref={receiptRef}>{order.summary}</article>
</>
);
}
Important client-side edge cases
- Cross-origin images may be omitted or taint the canvas unless the image server supplies appropriate CORS headers and the request is configured for CORS.
- Very tall pages consume substantial memory because the rendered bitmap must exist in the browser. Split large reports or move generation server-side.
- Use CSS page-break rules and the library’s page-break options, then inspect several pages. A canvas snapshot cannot reproduce every browser layout feature.
- Do not call this code during server-side rendering. Import and execute it only in a browser event or a client-only module.
- Choose JPEG only when its compression artifacts are acceptable. Text-heavy documents generally benefit from a high-quality setting, but the fundamental output remains image-based.
Option 3: generate PDFs with Puppeteer
Puppeteer drives a Chromium browser and exposes page.pdf(). This is suitable for an API endpoint, queue worker or build process that loads a URL or HTML template and returns a file. PDF generation uses print CSS media. If your design is written for screen media, emulate screen media before calling page.pdf().
Minimal Node.js service
import express from "express";
import puppeteer from "puppeteer";
const app = express();
app.use(express.json());
app.post("/pdf", async (req, res) => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900, deviceScaleFactor: 1 });
await page.goto(req.body.url, { waitUntil: "networkidle0" });
await page.emulateMediaType("print");
const pdf = await page.pdf({
format: "A4",
printBackground: true,
margin: { top: "12mm", right: "12mm", bottom: "12mm", left: "12mm" },
preferCSSPageSize: true
});
res.type("application/pdf").send(pdf);
} catch (error) {
res.status(500).json({ error: "PDF generation failed" });
} finally {
await browser.close();
}
});
app.listen(3000);
In production, launch one browser per worker or reuse a managed browser rather than launching a new process for every request. Limit concurrent pages, set navigation and generation timeouts, authenticate private pages safely, and close pages in a finally block. Never pass arbitrary user-supplied URLs to a server browser without SSRF protection.
Print CSS and readiness
Use @media print and @page for paper layout. Wait for application data and fonts before generating. A reliable pattern is to render a marker such as data-pdf-ready="true", then wait for that selector from Puppeteer. Network-idle alone does not prove that a React effect or chart has finished.
Option 4: generate PDFs with Playwright
Playwright offers Chromium, Firefox and WebKit automation and a page PDF method. Like Puppeteer, it creates PDFs with print CSS media. Its browser-context model is useful when each job needs isolated cookies, permissions or locale settings.
import { chromium } from "playwright";
const browser = await chromium.launch();
const context = await browser.newContext({ locale: "en-US" });
const page = await context.newPage();
try {
await page.goto("https://example.com/report", { waitUntil: "networkidle" });
await page.waitForSelector('[data-pdf-ready="true"]');
await page.pdf({
path: "report.pdf",
format: "A4",
printBackground: true,
preferCSSPageSize: true,
margin: { top: "12mm", right: "12mm", bottom: "12mm", left: "12mm" }
});
} finally {
await context.close();
await browser.close();
}
Install the package and the browser binaries required by your chosen Playwright version. In containers, verify sandbox permissions, installed fonts and shared libraries; a locally working script can fail in a minimal image because Chromium cannot start or a font is missing.
How to decide between the four approaches
Choose react-to-print when the user should remain in control
This is the right fit for a print button, receipts or reports where users expect the familiar browser preview and may change destination or paper settings. It avoids shipping a PDF engine, but it cannot guarantee a silent download or identical output across devices.
Choose html2pdf.js for small, offline-friendly exports
Use it when the data is already in the browser, no server browser is available, and an image-based PDF is acceptable. Confirm that users do not need to search or copy text and watch memory use for long documents.
Rank #3
Choose Puppeteer or Playwright for automated delivery
Use a headless browser when PDFs must be generated on demand without user interaction, attached to email, archived or produced by a queue. Build for browser startup cost, concurrency, timeouts, fonts, authentication and security. Puppeteer centers on Chromium; Playwright can automate multiple browser engines, although PDF output still depends on the browser used by the job.
Free tools Windows power users keep installed
One-click scans. No signup required.
Shared implementation checklist
- Define the output contract: paper size, orientation, margins, background colors, page numbering and whether text must be selectable.
- Keep print styles separate from interactive controls. Hide buttons, menus, hover-only affordances and transient alerts.
- Wait for data, images, web fonts and charts. Add an explicit readiness marker for automation.
- Test long tables, intentional page breaks, repeating headers, orphaned headings and images near page boundaries.
- Use deterministic locale, timezone and currency settings for server jobs.
- Protect private routes and never allow unrestricted URL fetching from a public PDF endpoint.
- Record the package, browser and operating-system versions used to generate archived documents.
Troubleshooting common failures
The PDF is blank or missing late content
The capture happened before React finished rendering or before data arrived. Add a readiness selector, wait for it, and verify that the URL is authenticated in the same browser context.
Styles look different from the page
PDF methods use print media. Add explicit @media print rules, enable background printing where supported, and check whether a style depends on an ancestor that is not part of the printed subtree.
Images disappear
Check CORS response headers, image authentication and lazy-loading behavior. For automation, wait for image completion; for canvas conversion, ensure cross-origin images are permitted.
Text cannot be selected
That is expected for a canvas-based html2pdf.js export in many cases. Use browser print or a headless-browser PDF when searchable text is a requirement.
Recommended Free Tools
Rank #4
Mobile users cannot print
Mobile WebViews and Firefox for Android have documented limitations in the react-to-print project. Offer a server-generated PDF or a download path for those environments and test the exact WebView wrapper.
Chromium fails to start in a container
Install the browser dependencies and fonts required by your automation package, check sandbox configuration, and capture the browser’s startup stderr. Do not “fix” this by disabling security globally without understanding the container isolation.
Jobs time out or exhaust memory
Set navigation and PDF timeouts, cap concurrency, reuse a browser process, close contexts promptly and split exceptionally large documents. Measure queue wait and browser memory in your own deployment; the available documentation does not establish a universal performance benchmark.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server when you need a clean image or PDF from a URL rather than maintaining your own browser automation. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →One GET request returns a PNG, JPEG, WebP or PDF. The API supports full-page captures with lazy images loaded, CSS-element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and page options, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for response and option details. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.
Best Value
FAQ
Can react-to-print download a PDF without opening print preview?
Not by itself. It invokes the browser print flow; use its custom print hook to connect the content to another generator if you need an automated file.
Does html2pdf.js work in a Node.js API route?
No. It depends on browser APIs, html2canvas and jsPDF. Use Puppeteer or Playwright for server-side browser generation.
Which option preserves selectable text?
Browser print and headless-browser PDF generation are the approaches to evaluate first. Canvas-based output from html2pdf.js may be image-based and therefore not selectable or searchable.
Do Puppeteer and Playwright use screen styles for PDF output?
They generate with print CSS media. In Puppeteer, explicitly emulate screen media first when the intended design is the screen stylesheet rather than the print stylesheet.
Frequently Asked Questions
Can react-to-print download a PDF without opening print preview?
Not by itself. It invokes the browser print flow; use its custom print hook to connect the content to another generator if you need an automated file.
Does html2pdf.js work in a Node.js API route?
No. It depends on browser APIs, html2canvas and jsPDF. Use Puppeteer or Playwright for server-side browser generation.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWhich option preserves selectable text?
Browser print and headless-browser PDF generation are the approaches to evaluate first. Canvas-based output from html2pdf.js may be image-based and therefore not selectable or searchable.
Do Puppeteer and Playwright use screen styles for PDF output?
They generate with print CSS media. In Puppeteer, explicitly emulate screen media first when the intended design is the screen stylesheet rather than the print stylesheet.
Quick Recap
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.

