Takumi

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-pdf

Render 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 },
});
OptionTypeDefaultDescription
size"a4", "letter", or { width, height }"a4"Page size in CSS px at 96 dpi. Presets ignore case.
landscapebooleanfalseSwaps page width and height, including explicit sizes.
marginnumber or { top?, right?, bottom?, left? }48A 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

On this page