Introduction
Export the React you've already built to a real vector PDF — no headless browser, no second component language.
You've already built the screen. Your invoice, statement, receipt, or report renders in the browser, looks the way the designer drew it, prints from Chrome, and your QA team has stopped filing tickets about it.
Then product says: "can users download a PDF?"
That single feature usually triggers one of three sad architectures: spin up a Chromium fleet on the server and pray it doesn't OOM; rebuild the whole document in a parallel renderer with its own CSS subset; or screenshot the screen to a canvas and ship a fuzzy image where the text used to be selectable.
react-print-pdf is the fourth option. It takes the DOM the browser already painted and emits a real vector PDF in the same tab — selectable text, embedded fonts, hyperlinks, the works. No server, no second renderer, no canvas blur.
pdf-lib.What this is
A small library that:
- runs in the browser (no Node, no server fleet)
- reads the DOM your existing React component already laid out
- emits PDF primitives via
pdf-lib— selectable text, embedded TTF/OTF fonts, real PNG/JPEG images, real hyperlinks - handles pagination, repeating headers and footers, manual page breaks
- falls back to raster for the handful of effects that don't translate cleanly (gradients, shadows, filters, SVG roots)
- ships React DX: a
usePDFExporthook, a<Printable>wrapper, an<ExportButton>
It does not:
- ask you to rewrite anything
- need its own component language
- require a server
- give up on selectable text because of a single drop shadow
Why bother
Most teams arrive at PDF after they already own a document UI: React components, Tailwind utilities, design tokens, branded tables, typography rules. Throwing that work away to "do PDF properly" is the most expensive option, not the cleanest.
Here's how the common paths trade off:
| Tooling path | What you get | What you pay |
|---|---|---|
| Headless Chromium | Accurate screenshots or print output | Server fleet, cold starts, ~200MB binaries, operational overhead |
Parallel renderers (e.g. @react-pdf/renderer) | Browser-independent PDF generation | A second layout/component system and a smaller CSS subset |
| Canvas screenshot export | Visual fidelity | Blurry text, no selection, large files, inaccessible output |
| react-print-pdf | Browser layout + vector PDF primitives | Browser-only for v1, plus a short list of honest limitations |
How it actually works
Five stages. You only write the first one — the browser does stage two for free, we do stages three through five.
- You render. A regular React component. Tailwind, CSS modules, whatever you already use.
- The browser paints. Computed styles, font metrics, line wrapping, table layout — already solved, already in the DOM.
- We walk. We read every box, every text rectangle, every image, every border, and tag the regions that need raster fallback.
- We paginate. Split the captured tree into pages, repeat your header and footer, honor
break-before/break-after/break-inside: avoid. - We emit.
pdf-libdoes the byte serialization, fonts get subset, images get embedded, links become clickable annotations.
Want the longer version with examples? Read How it works. Want to ship something today? Quick start takes three minutes.
What's vector today
Everything the browser draws with shapes and text, we draw with shapes and text:
- text runs from
Range.getClientRects()— exactly where the browser put them - solid backgrounds, including ones that continue across page breaks
- borders, including per-side colors and rounded corners
- hyperlinks: every
<a href>becomes a clickable PDF Link annotation - PNG and JPEG images as PDF image XObjects (real bytes, not screenshots)
- registered TTF/OTF fonts, subset into the final PDF
- pagination, headers, footers, explicit breaks, repeat bands
- true alpha — semi-transparent fills compose correctly against everything underneath
What falls back to raster
Some browser effects are expensive or unreliable to recreate as PDF vectors. The library automatically captures those regions as PNGs at high DPI:
- gradients
- shadows
- CSS transforms
- filters
- SVG roots
- anything you tag manually with
data-pdf-raster="true"
The goal isn't ideological purity — it's a PDF that stays mostly vector while preserving the parts the browser can draw better than a hand-rolled PDF emitter could.
Status
Public, MIT-licensed, semver-stable from 0.2.0.
- Current channel:
0.2.0on npm under thelatestdist-tag - Scope: browser-only, React-only for v1
- API shape: pass an
HTMLElementtoexportToPDF, or use the React DX layer (usePDFExport,<Printable>,<ExportButton>) - Honest about gaps: the Limitations page is short, current, and not buried
Where to next
| If you want to | Go here |
|---|---|
| See it work in three minutes | Quick start |
| Understand the export pipeline | How it works |
| Copy a real-world example | Examples |
| Know what to avoid before production | Best practices → Limitations |
| Wire your AI coding tool | AI guide |