Generate PDFs
Render JSX, HTML, or node trees to PDF with takumi-pdf.
takumi-pdf renders JSX, HTML, and node trees to PDF. Use CSS and Tailwind to lay out the document, then save the returned bytes or send them in an HTTP response. The WebAssembly renderer runs without a browser process.
npm i takumi-pdf @takumi-rs/helpers reactRender a document
import { } from "takumi-pdf";
import { , } from "takumi-pdf/primitives";
import { } from "@takumi-rs/helpers";
import { } from "node:fs/promises";
const = await (
<>
<>Invoice 1042</>
<>Total: $1,290</>
</>,
{
: "a4",
: await (["Inter"]),
: (
< ="flex w-full justify-center text-[10px] text-gray-500">
Page < /> of < />
</>
),
},
);
await ("invoice.pdf", );render() returns a Uint8Array. By default, it flows content across A4 pages with automatic margins. Body text stays selectable, and registered fonts are embedded as subsets. SVG labels are drawn as outlines.
HTML strings use the same parser as takumi-js. A <style> tag in the string applies only to that render:
import { } from "takumi-pdf";
const = await (`
<style>.total { font-weight: 700 }</style>
<div><span class="total">Total: $1,290</span></div>
`);Headers, footers, and measure() accept the same inputs.
Page setup
import { } from "takumi-pdf";
const = await (, {
: "letter", // a page keyword, or { width, height } in CSS px at 96 dpi
: true,
: { : 48, : 32, : 48, : 32 },
});| Option | Type | Default | Description |
|---|---|---|---|
size | a page keyword or { width, height } | "a4" | Page size in CSS px at 96 dpi. Keywords ignore case. |
landscape | boolean | false | Swaps page width and height, including explicit sizes. |
margin | number, "auto", or { top?, right?, bottom?, left? } | "auto" | "auto" fits the band on that side, and a side left out of the object is "auto" too. |
backgroundColor | CSS color | unset | Fills the page box, margins included, under everything. |
size accepts these paper sizes. Each keyword uses portrait orientation:
| Keyword | Size | Keyword | Size |
|---|---|---|---|
"a3" | 297 × 420 mm | "jis-b4" | 257 × 364 mm |
"a4" | 210 × 297 mm | "jis-b5" | 182 × 257 mm |
"a5" | 148 × 210 mm | "ledger" | 11 × 17 in |
"b4" | 250 × 353 mm | "legal" | 8.5 × 14 in |
"b5" | 176 × 250 mm | "letter" | 8.5 × 11 in |
Set landscape to turn any of them, or pass { width, height } for a size with no keyword.
Set page geometry through these options. CSS @page rules are not parsed.
Automatic top and bottom margins fit the header or footer, including its 20px inset from the paper edge. They are at least 37.8px on ordinary page sizes. Without a header or footer, the default is 37.8px (1cm). See Headers and footers.
Leave backgroundColor unset for white paper.
A viewer draws white by default, and the file stays free of a full-page rectangle.
Reuse a renderer
render() reuses a shared renderer. Create a PdfRenderer when you need a separate font registry:
import { } from "takumi-pdf";
const = new ();
await .("https://example.com/fonts/Inter-Regular.woff2");
const = await .();Registered fonts are deduplicated across calls. Replace the example URL with your font file.
Runtimes
Use the default import on Node.js, Bun, and Cloudflare Workers. For manual initialization, import takumi-pdf/no-init.
Next.js
Import takumi-pdf/next in a Next.js route handler. This entry supports the Node and Edge runtimes without a serverExternalPackages entry.
import { render } from "takumi-pdf/next";In the browser
For browser bundles, initialize the renderer with takumi-pdf/no-init and takumi-pdf/wasm-url:
import init, { render } from "takumi-pdf/no-init";
import wasmUrl from "takumi-pdf/wasm-url";
await init({ module_or_path: wasmUrl });takumi-pdf/wasm-url resolves the binary with new URL(specifier, import.meta.url).
Vite, webpack, and Turbopack rewrite that call to the asset they emit.
The module has no top-level await, so it also works in a worker bundled as an IIFE.
Server code should keep the default entry. A Vite SSR build leaves the URL pointing at the server chunk, where the asset never lands.
On Turbopack, drop any turbopack.rules entry mapping *.wasm to type: "wasm".
That rule makes Turbopack instantiate the binary and look for wasm-bindgen glue the
package does not ship.
Choose the next guide
| Task | Guide |
|---|---|
| Control page breaks and repeated table headers | Pagination |
| Add page numbers | Headers and footers |
| Load fonts, logos, and photos | Fonts and images |
| Add links or a table of contents | Links, outline, and metadata |
| Create a receipt or label | Single-page viewport |
| Generate archival or accessible output | PDF/A and PDF/UA |
For complete document patterns, see Invoices, Reports, and Charts.
Last updated on