Introduction
Render JSX to paged, selectable-text PDF with takumi-pdf.
takumi-pdf renders the same JSX, Tailwind classes, and node trees as image output. It writes a paged vector PDF instead: selectable text, embedded subset fonts, page breaks, and repeating headers and footers. It ships as a WebAssembly module. It runs on Node.js, Bun, and Cloudflare Workers without Chromium.
npm i takumi-pdfRender a document
import { } from "takumi-pdf";
import { } from "@takumi-rs/helpers";
import { } from "node:fs/promises";
const = await (< ={} />, {
// A4 portrait with a 48px margin is the default
: "a4",
: await (["Inter"]),
: (
< ="flex w-full justify-center text-[10px] text-gray-500">
Page < ="pageNumber" /> of < ="totalPages" />
</>
),
});
await ("invoice.pdf", );render() accepts JSX, HTML strings converted with @takumi-rs/helpers, or JSON node trees. It returns Uint8Array PDF bytes. Content lays out at the page's content width. It flows onto as many pages as needed.
Page setup
const = await (, {
: "letter", // "a4", "letter", or { width, height } in CSS px at 96 dpi
: true,
: { : 48, : 32, : 48, : 32 },
});| Option | Type | Default | Description |
|---|---|---|---|
size | "a4", "letter", or { width, height } | "a4" | Page size in CSS px at 96 dpi. Presets ignore case. |
landscape | boolean | false | Swaps page width and height, including explicit sizes. |
margin | number or { top?, right?, bottom?, left? } | 48 | A number applies to all sides. Missing object sides are 0. |
@page CSS rules are not supported. Use these options to set the page geometry.
Reuse a renderer
render() keeps one shared renderer alive. Construct PdfRenderer directly for applications that manage several font sets:
import { } from "takumi-pdf";
const = new ();
await .("https://example.com/Inter-Regular.woff2");
const = await .();Registered fonts deduplicate across calls. Rendering many documents pays the font cost once.
Last updated on