Skip to content

§ React to PDF

React to PDF: Convert a React Component or Page to a Real PDF

Turn a React component, a rendered page, or raw HTML into a pixel perfect PDF with one API call. Managed Chromium renders your real markup, so text stays selectable and your Tailwind and web fonts survive, no html2canvas screenshot, no browser to run yourself. Try it on any URL below.

  • Early access, launching soon
  • No card required
  • Your HTML stays yours

§ Live demo

Runs in your browser. Nothing is uploaded.

Your PDF is downloading. Want this as one API call, with the page archived too?

§ Short answer

The reliable way to convert React to PDF for production is to render your real React output in a browser on the server, not to screenshot the DOM in the client. Client-side tools like react-to-pdf and html2canvas take a raster snapshot: the text is not selectable, it pixelates when zoomed, and Tailwind v4 oklch() colors break the capture outright. Sitepdf renders the same HTML your React app produces in managed Chromium and returns a true, searchable vector PDF, plus an optional timestamped archive of exactly what was rendered.

Last updated July 2026. Written and fact checked by the Sitepdf team.

§ 00

Three ways to get a PDF out of React, compared

React has no built in PDF export, so every team picks one of these three approaches. They differ most in whether the PDF contains real text and whether your app CSS actually applies.

Approach How it works Output Modern CSS and Tailwind v4 Best for
@react-pdf/renderer You rewrite the layout as its own JSX primitives (View, Text) True vector PDF No: its own layout engine, your app CSS does not apply Designing a PDF from scratch, not reusing a page
react-to-pdf, html2canvas + jsPDF
client side
Snapshots a DOM node in the browser and drops the image into a PDF Raster image, text not selectable, pixelates on zoom Breaks: oklch() colors throw, gradients and shadows drift A quick client export of one simple, static screen
Server side Chromium API
Sitepdf
Renders your real page or HTML in a managed browser True searchable vector PDF, print accurate Full support, it is a real current browser Production documents, identical output for every user, a dated record

The honest read: @react-pdf/renderer is excellent when the PDF is a distinct design you build in JSX, and it is genuinely the right tool for that. If instead you want the PDF to look like the page your users already see, a real browser has to do the rendering, which is why the client screenshot route keeps disappointing teams once fonts, charts and Tailwind enter the picture.

§ 01

Why the client-side screenshot route keeps letting teams down

The most common first attempt is react-to-pdf or a hand rolled html2canvas plus jsPDF combination. It is appealing because it runs entirely in the browser and needs no backend. It also quietly produces a worse document than people expect. Under the hood these libraries paint the component onto a canvas and embed that canvas as an image, so the PDF is a picture of your UI. The text inside cannot be selected, copied or searched, it turns fuzzy the moment someone zooms in, and it does not reflow, so a tall report becomes one enormous image awkwardly sliced across pages.

Then there is the CSS problem that arrived with Tailwind v4. Tailwind now emits colors in the oklch() function, and html2canvas cannot parse it, so the capture fails with "Attempting to parse an unsupported color function oklch". You can patch it by overriding every color at render time, but that is a maintenance tax you pay forever. A real browser has none of these limits because it is the same engine that drew the page in the first place.

§ 02

The server-side path: render your real React output, keep real text

The fix is to move the rendering off the client and into a real browser. You have two clean ways to feed Sitepdf. If the document is a live route in your app, an invoice page, an order confirmation, a dashboard export, point the API at that URL and it loads the page in managed Chromium exactly as a visitor would, runs your JavaScript, waits for your charts, and returns the PDF. If you would rather not expose a route, render the component to an HTML string on the server with renderToStaticMarkup from react-dom/server and post that HTML instead.

import { renderToStaticMarkup } from "react-dom/server";
import Invoice from "./Invoice";

const html = renderToStaticMarkup(<Invoice data={invoice} />);

const res = await fetch("https://api.sitepdf.com/v1/render", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.SITEPDF_KEY}` },
  body: new URLSearchParams({ html, format: "Letter", archive: "true" }),
});
const { pdf_url } = await res.json();

Either way the browser does the layout, so your Tailwind classes, CSS grid, web fonts and background colors all render the way they do on screen, and the resulting text is real, selectable and searchable. Our HTML to PDF in Node.js guide covers the same call from an Express or Next.js API route, and the PDF generator API page has the full parameter list.

§ 03

When @react-pdf/renderer is the better choice

We are not going to pretend the API is always the answer. If your PDF is a bespoke document that looks nothing like any page in your app, a shipping label, a certificate, a fixed format statement, then @react-pdf/renderer is a genuinely good fit and it costs nothing. You describe the document with its own <View> and <Text> primitives, and because it never touches a browser it is fast and has no infrastructure. The catch is exactly that separation: it ignores your existing CSS, so you are rebuilding the layout in a second styling system, and complex responsive designs are painful to express in its subset.

So the rule is simple. Reusing a page or a template your users already see, and you want it to match? Render it in a real browser. Building a brand new document layout from scratch in code, with no HTML to reuse? @react-pdf/renderer earns its place. The screenshot libraries are the one option that rarely wins on a document that matters, because they trade away real text for convenience.

§ 04

Keep a dated copy of what you generated

There is one thing no React library gives you, on the client or the server: a record. When you generate an invoice, a receipt or a signed quote, the file goes to the customer and nothing verifiable stays with you. Add archive=true to the render call and Sitepdf also stores a timestamped, immutable snapshot of exactly what it rendered, retrievable by id later. For finance, legal and compliance work that provenance is often the reason to render server side in the first place. The website archiving page explains how the record works, the Vue to PDF and Angular to PDF pages walk the same trade offs for the other big component frameworks, and if you are weighing running your own headless Chrome instead, the Puppeteer alternative page runs that trade off honestly. Renders are transient by default; leave archiving off and we return the PDF and store nothing.

Point the API at a rendered React route, or post HTML you rendered on the server.
curl https://api.sitepdf.com/v1/render \
  -H "Authorization: Bearer $SITEPDF_KEY" \
  -F url=https://app.example.com/invoices/8842 \
  -F format=Letter \
  -F wait_for="#invoice-total" \
  -F archive=true

{
  "pdf_url": "https://api.sitepdf.com/v1/documents/doc_9r2la.pdf",
  "pages": 2,
  "rendered_in_ms": 1740,
  "archive": {
    "id": "arc_k70bd",
    "captured_at": "2026-07-19T18:04:12Z",
    "retrieve_url": "https://api.sitepdf.com/v1/archives/arc_k70bd"
  }
}

The API is in early access; this is the documented call shape it opens with. Full request and response walkthrough.

§ 05

Questions about this job

How do I convert a React component to PDF?
Render the component to HTML on the server with renderToStaticMarkup, or point a rendering API at the live route that shows it. A real browser then converts that HTML to a PDF, so the text stays selectable and your CSS applies. Avoid client-side html2canvas snapshots for anything important, because they embed an image, not real text.
Why is my react-to-pdf output blurry or not selectable?
Because react-to-pdf and html2canvas take a raster screenshot of the DOM and place that image in the PDF. An image has no real text to select and it pixelates when zoomed. To get a crisp, searchable PDF you need a browser to render the page to PDF directly, which is what a server-side Chromium API does.
Does html2canvas work with Tailwind v4?
Not out of the box. Tailwind v4 emits colors with the CSS oklch() function, and html2canvas cannot parse it, so the capture throws an unsupported color function error. You can override colors at render time as a workaround, or render server side in a real browser, which supports oklch natively and needs no patching.
Should I use @react-pdf/renderer or a rendering API?
Use @react-pdf/renderer when the PDF is a bespoke layout you build in JSX and it does not need to match an existing page. Use a rendering API when you want the PDF to look like a page your users already see, with your real Tailwind, fonts and charts, or when you need a dated record of each document.
Can I generate the PDF from a Next.js API route?
Yes. In a Next.js route handler you either post the HTML you rendered with renderToStaticMarkup, or pass the URL of a rendered page, to the render endpoint and stream back the PDF. Nothing runs a browser inside your function, which is what makes it work on serverless hosts where you cannot launch Chromium.

§ Early access

Get on the early-access list

The API opens to the list first, in order. Early access locks the planned launch rates for 12 months. No card required, launching soon.

Render + archive, one API