Skip to content

Generate PDFs in React

Connect a React form to a PDF preview with fullbleed/browser. Change a field or an HTML/CSS template and the actual PDF updates after a short pause. The engine renders in a browser worker; this starter needs no PDF server or account.

Open the React demo Download the React project

The project includes a designed invoice, a three-page report, a React form and template editor, and a reusable TypeScript hook. Its sample names, records, and amounts are fictional. The code is MIT licensed, including commercial use.

Run the project

Extract the ZIP. With Node.js 22.12 or newer, open a terminal in fullbleed-react-starter and run:

npm ci
npm run dev

Open the localhost URL printed by Vite. Edit the customer, reference, or ink color and wait for Ready. Download PDF saves the generated document. Turn off Update automatically to generate only when you choose Generate PDF. Cancel stops a pending preview or active render.

The lockfile pins Fullbleed npm 0.3.0 / engine 2.5.8, React 19.3.0, TypeScript 7.0.2, and Vite 8.3.2. The ZIP includes its source and lockfile; the build downloads the published dependencies and copies their verified runtime.

Customize the document

Open Edit the HTML & CSS to paste a print template. Changes stay in the tab until reload or closing the editor. Keep a design by editing these project files:

File Purpose
src/App.tsx React fields, structured data, template selection, and preview UI
src/usePdfPreview.ts Rendering, cancellation, stale-result protection, and URL cleanup
src/invoice.html / src/invoice.css Invoice print layout
src/report.html / src/report.css Three-page report print layout
src/style.css The application interface

The invoice fills {{customer}} and {{reference}} in HTML and {{ink}} in CSS. The app escapes customer text before inserting it. Line items, amounts, dates, and addresses are fixed samples: replace them with your data and calculations.

Use supported Fullbleed print CSS. The SDK consumes static HTML/CSS rather than capturing the React page. Document scripts do not execute, and document URLs do not fetch remote resources. Pass extra font or image bytes through the SDK's fonts and assets options.

Reuse the hook in an existing React app

Install the package and copy its runtime into your app's static directory:

npm install --save-exact fullbleed@0.3.0
npx fullbleed-browser-assets public/fullbleed

Copy src/usePdfPreview.ts from the project into your client app. Memoize its input so unrelated component updates do not schedule a new render:

import { useMemo } from 'react';
import { usePdfPreview } from './usePdfPreview';

export function PdfDownload({ html, css }: { html: string; css: string }) {
  const input = useMemo(() => ({
    html, css, previewDpi: 96, maxPages: 20, timeoutMs: 30_000,
  }), [html, css]);
  const pdf = usePdfPreview(input, '/fullbleed/');

  return <section>
    <p role="status">{pdf.error?.message ?? pdf.status}</p>
    <button onClick={pdf.cancel}>Cancel</button>
    {pdf.result && <>
      <a href={pdf.result.url} download="document.pdf">Download PDF</a>
      {pdf.result.previews.map((url, index) =>
        <img key={url} src={url} alt={`PDF page ${index + 1}`} />)}
    </>}
  </section>;
}

The default delay is 450 ms. Use the third argument { auto: false } and call pdf.generate() from a button for on-demand rendering. { delayMs: 800 } waits longer between edits. A new input immediately hides the old download, cancels the preceding job, and schedules the next preview. Cancel stops work until the next edit or explicit generate() call. Changing preview mode resets output.

The hook releases old PDF/PNG Blob URLs and aborts active work on unmount. It ignores obsolete results even when requests settle out of order. The starter uses React StrictMode, including the extra setup/cleanup cycle in development; see React's Effect cleanup guidance. Use it in a client component with browser APIs available.

Build and deploy

npm run build
npm run preview

Upload the complete dist/ directory to a static HTTPS host. The example uses relative paths and is checked under a nested URL prefix. In another app, set the hook's asset URL to your same-origin runtime directory, ending in /. Keep the client, worker, engine, fonts, manifest, and notices together.

The deployed app needs no Node process. Its first render loads the engine and fonts from the static host; document inputs stay in the same browser. It needs HTTPS or localhost, Web Workers, WebAssembly, and Web Crypto. The browser SDK guide covers hosting, custom assets, and API limits.

What is checked

The source workflow checks the built project in Chrome, Firefox, and Playwright WebKit, and checks a React development build with StrictMode enabled. It downloads real PDFs, independently checks their text and page sizes, and compares the default invoice and report bytes with the installed Node package. It also checks automatic and on-demand modes, fast edits, cancellation, recovery, unmount/remount, URL cleanup, and 1440/390/320px layouts. The docs build installs and checks the exact ZIP.

These fixtures do not establish compatibility with every browser, device, or hosting policy. WebKit testing is not branded Safari certification. Worker observations count browser API handles; browsers expose no native thread-exit promise. Bound concurrently mounted renderers for the devices you support.

This browser entry provides ordinary PDFs and previews, not PDF/A, PDF/UA, PDF/X, or VDP options. For a server-side React framework route, use the Next.js PDF download starter.