pdfnative-react
v0.2.0
Published
React renderer for pdfnative — declarative JSX components (<Document>, <Page>, <Table>, <Barcode>…) that compile to PDF on-device with zero SaaS round-trips. Live preview, streaming, 22 Unicode scripts. The frontend gateway to the pdfnative ecosystem.
Downloads
286
Maintainers
Readme
pdfnative-react
Write PDFs the way you write UIs. pdfnative-react turns declarative JSX into
real, on-device PDF documents powered by the zero-dependency
pdfnative engine — no DOM, no
headless browser, no SaaS round-trips. Your documents never leave the process.
import { Document, Heading, Text, Table, renderToBytes } from 'pdfnative-react';
const bytes = renderToBytes(
<Document title="Invoice #1024" footerText="Acme Inc">
<Heading level={1}>Invoice #1024</Heading>
<Text>Thank you for your business.</Text>
<Table
headers={['Item', 'Qty', 'Total']}
rows={[
{ cells: ['Pro plan', '1', '$49.00'], type: 'default', pointed: false },
]}
zebra
/>
</Document>,
);
// → Uint8Array, a valid PDF (%PDF-… …%%EOF)Why pdfnative-react
- Declarative & familiar. Components mirror
@react-pdf/rendererergonomics (Document,Page,Text,Image,Link,usePdf,PDFViewer,PDFDownloadLink,BlobProvider). - On-device. A custom React reconciler compiles your tree — synchronously,
with no DOM — to the
pdfnativemodel and renders the bytes locally. - Honest model. Components map 1:1 onto pdfnative blocks. There is no
CSS/flexbox engine and no
<View>— it is a declarative block flow. - Token-frugal AI authoring. A compact
DocSpeclets LLM agents emit documents with a fraction of the tokens of JSX, validated by a versioned JSON Schema — see Agent authoring. - Typed, tested, tree-shakeable. Strict TypeScript, dual ESM + CJS, source maps, provenance-signed publishes.
Install
npm install pdfnative-react pdfnative reactRequires React 19 and Node.js ≥ 20.
Components
Every component maps 1:1 onto a pdfnative block.
| Component | Renders |
|---|---|
| Document | The required root (title, footerText, metadata, fontEntries, layout). |
| Page | An explicit page boundary (content auto-paginates otherwise). |
| Heading | A section heading (level 1–3); feeds the auto TableOfContents. |
| Paragraph / Text | A wrapping paragraph (fontSize, lineHeight, align, indent, color). |
| List / Item | A bullet or numbered (ordered) list. |
| Table / Row / Cell | A data table (data-driven headers/rows, or JSX <Row>/<Cell>). |
| Image | An embedded JPEG/PNG (data: Uint8Array). |
| Link | A clickable hyperlink (url/href). |
| Spacer | Vertical whitespace (height). |
| PageBreak | A hard page break. |
| TableOfContents / Toc | An auto-generated TOC built from headings. |
| Barcode | QR, Code 128, EAN-13, PDF417, Data Matrix (format, data). |
| Svg | Inline vector graphics (path data or markup). |
| FormField | Interactive AcroForm widgets (fieldType, name). |
Rendering
import {
renderToBytes, // (node, options?) => Uint8Array
renderToBlob, // (node, options?) => Blob (application/pdf)
renderToStream, // (node, options?) => AsyncGenerator<Uint8Array> (constant memory)
renderToFile, // (node, path, options?) => Promise<void> (Node only)
compileDocument, // (node) => DocumentParams (inspect the model, no render)
} from 'pdfnative-react';options is { layout?: Partial<PdfLayoutOptions>; fontEntries?: FontEntry[] }
and merges on top of anything set on <Document> — page size, margins, colors,
PDF/A mode, encryption, and non-Latin fonts.
Hooks & client components
Client modules carry 'use client'.
'use client';
import { usePdf } from 'pdfnative-react';
function Preview({ doc }: { doc: React.ReactElement }) {
const { url, loading } = usePdf(doc);
return loading ? <p>Rendering…</p> : <iframe title="preview" src={url} />;
}usePdf(element, options?)→{ url, blob, bytes, loading, error, update }usePdfStream(element, options?)→{ getStream() }PDFViewer— live<iframe>preview.PDFDownloadLink— one-click download (supports a render-prop child).BlobProvider— render-prop access to the rawBlob.
Agent authoring (token-frugal)
pdfnative-react is a library, so the place LLM agents spend tokens is
authoring documents. The compact DocSpec expresses the same document as
terse, JSON-serializable tuples — and compiles to the exact same PDF as the
JSX, because it is built on the very same components.
import { renderSpecToBytes, type DocSpec } from 'pdfnative-react';
const spec: DocSpec = {
title: 'Invoice #1024',
footerText: 'Acme Inc',
blocks: [
['h1', 'Invoice #1024'],
['p', 'Thank you for your business.', { align: 'right' }],
['table', { h: ['Item', 'Total'], r: [['Pro plan', '$49.00']], zebra: true }],
['qr', 'https://acme.example/pay/1024', { align: 'right' }],
],
};
const bytes = renderSpecToBytes(spec);The equivalent JSX is several times more tokens for a typical document (the gap widens on larger ones), because every block carries opening/closing tags and prop names. Same bytes out, far fewer tokens in.
compileSpec(spec)→DocumentParams·specToElement(spec)→<Document>elementrenderSpecToBytes/renderSpecToBlob/renderSpecToStream/renderSpecToFiledocSpecSchema()→ a Draft 2020-12 JSON Schema whose$idembeds the package version, so agents can self-validate a spec before rendering.
Block tuples: ['h1'|'h2'|'h3', text, opts?], ['p', text, opts?],
['ul'|'ol', items, opts?], ['table', { h?, r }], ['img', { data }],
['link', text, { url }], ['sp', height?], ['br'], ['page', blocks],
['toc', opts?], ['qr'|'code128'|'ean13'|'pdf417'|'datamatrix', data, opts?],
['svg', data, opts?], ['field', { fieldType, name, … }].
Fonts & environment
Re-exported from the engine: registerFonts, registerFont, loadFontData
(Node), downloadBlob (browser), initNodeCompression (Node). Pass non-Latin
fonts via the fontEntries render option.
Migrating from @react-pdf/renderer
| @react-pdf/renderer | pdfnative-react |
|---|---|
| <Document> / <Page> | <Document> / <Page> |
| <Text> | <Text> (alias of <Paragraph>) |
| <View> + flexbox styles | (none — declarative block flow; use blocks + <Spacer>) |
| StyleSheet | per-component props (align, color, fontSize, …) |
| <PDFViewer> / <PDFDownloadLink> / <BlobProvider> | same names, same shape |
| usePDF() | usePdf() |
Examples
Runnable, type-checked examples live in samples/: typography, tables, images, links, barcodes, SVG, form fields, multi-page structure, custom fonts, layout/PDF-A, the client hooks/components, and the compact agent spec.
The pdfnative ecosystem
| Package | Use it for |
|---|---|
| pdfnative | The zero-dependency PDF engine — Node, browsers, Workers, Deno, Bun. |
| pdfnative-react | Declarative React/JSX components with live preview (this package). |
| pdfnative-cli | Render, sign, inspect, and verify PDFs from the shell. |
| pdfnative-mcp | Generate PDFs from Claude Desktop, Cursor, Continue, Zed. |
Documentation
- Knowledge Base — architecture, the compile pipeline, the react-reconciler version contract, and the agent authoring contract.
- AGENTS.md — guidance for AI agents working in this repo.
- CHANGELOG.md · ROADMAP.md · CONTRIBUTING.md
