October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
HTML to PDF

How to Convert HTML to PDF in React: Browser, Client-Side, and Server-Side Methods

Free tools Windows power users keep installed

One-click scans. No signup required.

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 React depends on what you are exporting. For an existing page that users can print, call window.print() and add print-only CSS. For a client-side download of one DOM element, use html2pdf.js. For invoices or reports that need a dedicated, predictable layout, build a separate document with @react-pdf/renderer. For automated server output from HTML, use Puppeteer and page.pdf(). React’s rendering APIs produce HTML, not PDF files, so they must be combined with one of these browser or PDF-generation workflows.

Choose the conversion route first

Decide whether the PDF should reproduce an existing React view or be authored as a separate document. Also decide where conversion runs and whether a person should control the final save.

Approach Best fit Where it runs Main trade-off
window.print() plus print CSS An existing page and a user who can use the print dialog Browser Minimal code; browser settings and the user complete the save workflow
html2pdf.js Downloading a selected element or page from the browser Browser Convenient options, but layout depends on the html2canvas/jsPDF pipeline
@react-pdf/renderer Invoices, reports, and other PDF-specific documents Browser or server You author PDF primitives instead of exporting arbitrary DOM
Puppeteer Page.pdf() Automated HTML-to-PDF generation Backend with a suitable browser runtime Strong server control; you operate Chromium automation

Validate a representative document in the exact browser or runtime you will ship. Documentation describes APIs and options, but cannot guarantee that your application’s fonts, assets, CSS, and page breaks will export correctly.

Method 1: let the browser print the React page

This is the simplest solution when a user can choose “Save to PDF” in the browser’s print dialog. window.print() opens that dialog for the current document; if the page is still loading, the browser finishes loading before showing it. MDN lists the API as widely available across devices and browser versions.

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

Add a print button

export default function PrintButton() {
  return (
    <button type="button" onClick={() => window.print()}>
      Print or save as PDF
    </button>
  );
}

Hide application chrome with print CSS

/* app.css */
@media print {
  .no-print,
  nav,
  button,
  .chat-widget {
    display: none !important;
  }

  @page {
    size: A4;
    margin: 16mm;
  }

  body {
    color: #000;
    background: #fff;
    font-size: 11pt;
  }

  a {
    color: #000;
    text-decoration: none;
  }

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

Use print media rules to remove navigation and interactive controls, adjust dimensions and colors, and control page breaks. The user still chooses the destination, paper size, margins, scale, backgrounds, and other options in the browser UI. Test with the target browser’s print preview rather than assuming screen CSS will carry over.

Method 2: download an element with html2pdf.js

html2pdf.js documentation describes a browser workflow that selects an element, passes options, and saves a file. It uses html2canvas and jsPDF, so it is an element-conversion pipeline rather than a new PDF document model.

Install and create a download component

npm install html2pdf.js
import html2pdf from 'html2pdf.js';

export function DownloadReport({ report }) {
  const download = () => {
    const element = document.getElementById('report');
    if (!element) return;

    const options = {
      margin: [10, 10, 10, 10],
      filename: `report-${report.id}.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']
      }
    };

    html2pdf().set(options).from(element).save();
  };

  return (
    <>
      <button type="button" onClick={download}>Download PDF</button>
      <article id="report">{report.content}</article>
    </>
  );
}

The documented options cover margins, filename, image type and quality, html2canvas settings, jsPDF units, paper format, orientation, and page-break modes. Add CSS such as .avoid-break { break-inside: avoid; } to keep cards together where the conversion engine honors it.

What to test

  • Long pages and tables that cross page boundaries.
  • Web fonts, images, SVG, and cross-origin assets.
  • Fixed or sticky elements, transforms, and complex filters.
  • Very large DOM trees, which can increase browser memory use.

Because html2canvas first represents the page for jsPDF, the result may differ from native browser printing. Inspect the actual PDF on the browsers and content types your application supports; do not promise pixel-perfect output from the package description alone.

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

Method 3: author a PDF with @react-pdf/renderer

Use @react-pdf/renderer when the PDF is its own document, not a copy of arbitrary existing DOM. Its React primitives include Document, Page, View, and Text, styled with JavaScript objects.

Browser download example

npm install @react-pdf/renderer
import {
  Document, Page, Text, View, StyleSheet, PDFDownloadLink
} from '@react-pdf/renderer';

const styles = StyleSheet.create({
  page: { padding: 32, fontSize: 11 },
  heading: { fontSize: 20, marginBottom: 12 },
  row: { marginBottom: 8 }
});

function InvoicePdf({ invoice }) {
  return (
    <Document>
      <Page size="A4" style={styles.page}>
        <Text style={styles.heading}>Invoice {invoice.number}</Text>
        {invoice.lines.map(line => (
          <View style={styles.row} key={line.id}>
            <Text>{line.description} — {line.amount}</Text>
          </View>
        ))}
      </Page>
    </Document>
  );
}

export function InvoiceDownload({ invoice }) {
  return (
    <PDFDownloadLink
      document={<InvoicePdf invoice={invoice} />}
      fileName={`invoice-${invoice.number}.pdf`}
    >
      {({ loading }) => loading ? 'Preparing…' : 'Download invoice'}
    </PDFDownloadLink>
  );
}

This approach gives you a PDF-specific representation that can be displayed or rendered on a server. It does not accept an existing HTML tree unchanged; you must map your data into the library’s document primitives. That extra modeling is worthwhile when stable pagination and a controlled document design matter more than reusing web markup.

Method 4: generate HTML PDFs on the server with Puppeteer

Puppeteer’s Page.pdf() API generates a PDF using print CSS media. Options include paper format, landscape mode, margins, backgrounds, page ranges, CSS page-size preference, scale, and waiting for fonts. The PDF generation guide shows opening a browser, navigating, saving the file, and closing the browser.

Express endpoint example

npm install puppeteer express
import express from 'express';
import puppeteer from 'puppeteer';

const app = express();

app.get('/reports/:id.pdf', async (req, res) => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto(`https://app.example.com/reports/${req.params.id}`, {
      waitUntil: 'networkidle0'
    });
    await page.emulateMediaType('print');
    await page.evaluate(() => document.fonts.ready);

    const pdf = await page.pdf({
      format: 'A4',
      printBackground: true,
      preferCSSPageSize: true,
      margin: { top: '16mm', right: '16mm', bottom: '16mm', left: '16mm' }
    });

    res.type('application/pdf').send(pdf);
  } finally {
    await browser.close();
  }
});

app.listen(3000);

Keep this code on a backend that can run the chosen Puppeteer browser. Protect authenticated pages and validate the URL or report identifier instead of accepting arbitrary navigation from a client. Ensure data, images, and fonts are ready before calling page.pdf(); otherwise the file can contain placeholders or missing assets. Use CSS @page rules together with preferCSSPageSize when the document defines its own paper size.

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

Why React rendering APIs do not create PDFs

React’s server APIs are HTML-producing steps. The renderToString reference states that “renderToString renders a React tree to an HTML string.” It has limited Suspense support, does not stream or wait for data, and is not recommended for client-side use. renderToStaticMarkup also returns HTML, but its output is non-interactive and cannot be hydrated. You can feed either result into a browser such as Puppeteer, but another PDF step remains necessary.

Reliability checklist before shipping

  • Choose a representative document containing your longest text, largest table, images, and custom fonts.
  • Wait for data, images, and document.fonts.ready before capture.
  • Define print colors, margins, paper size, and break rules explicitly.
  • Check links, selectable text, page count, headers, footers, and clipped content in the produced PDF.
  • Run the test in the production browser or server runtime, not only in a development tab.
  • Decide how private data is handled: browser-only methods keep content local, while server rendering sends it to your backend.

Troubleshooting common failures

The PDF is blank

Confirm that the target element exists, the route finished loading, and the browser has reached the intended state. In Puppeteer, inspect the response and wait for the relevant selector or network activity rather than relying on a fixed delay.

Fonts or images are missing

Use accessible asset URLs, wait for fonts and images, and configure cross-origin access where required by a client-side canvas pipeline. Verify that the server can reach every asset when using Puppeteer.

Content is cut off or overlaps

Replace screen-only fixed heights with content-driven sizing, add print break rules, and test tables and flex layouts across page boundaries. For a complex report, a PDF-specific renderer may be more predictable than converting arbitrary DOM.

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

Styles look different

Browser printing, html2pdf.js, and Puppeteer do not share identical rendering paths. Put print-specific rules in @media print, enable backgrounds where appropriate, and compare output in the exact target runtime.

The browser freezes during client conversion

Reduce the captured DOM, lower canvas scale or image quality, and split very large documents. Move conversion to a server workflow when browser memory is insufficient.

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

Or skip the browser setup

ScreenshotNeo is a website screenshot API that can return a PDF from one GET request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server includes take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for all options, including full-page capture, CSS-selector elements, print settings, custom CSS and JavaScript, waits, headers, cookies, user agents, authorization, timezone, geolocation, caching, signed links, asynchronous webhooks, bulk capture, and usage reporting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 shots each 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.

Which method should you use?

  • Choose browser printing when a person can review and save the current page.
  • Choose html2pdf.js for a client-side button that converts a bounded element.
  • Choose @react-pdf/renderer when the PDF is a separately designed business document.
  • Choose Puppeteer when your backend must generate PDFs automatically from HTML.

Frequently Asked Questions

Can I convert a React component directly with renderToString?

No. It returns an HTML string. Pass that HTML to a browser print or PDF pipeline such as Puppeteer, or use a PDF-specific renderer.

Is browser printing suitable for unattended downloads?

No. It depends on the user’s print dialog. Use html2pdf.js for a browser-controlled download or Puppeteer for an automated backend file.

Should an invoice use html2pdf.js or react-pdf?

Use react-pdf when you can model the invoice as a dedicated document and need predictable PDF structure; use html2pdf.js when reusing the existing invoice DOM is the priority.

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

How do I verify page breaks?

Export a representative long document in the production runtime and inspect tables, images, fonts, clipping, and break rules in the resulting PDF.

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.

Read next

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

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.