Takumi

From react-pdf

Move a @react-pdf/renderer template to takumi-pdf by mapping each component and option, converting units, and registering fonts and images.

To migrate, replace react-pdf's primitives with HTML elements, move page settings into render() options, and convert lengths from pt to CSS px. The resulting JSX also renders as an image with takumi-js.

Before and after

Before: react-pdf primitives
// @react-pdf/renderer
import { Document, Page, View, Text, StyleSheet, renderToBuffer, Font } from "@react-pdf/renderer";

Font.register({ family: "Inter", src: "./Inter-Regular.ttf" });

const styles = StyleSheet.create({
  page: { padding: 48, fontFamily: "Inter" },
  row: { flexDirection: "row", justifyContent: "space-between" },
  label: { fontSize: 10, color: "#6b7280" },
});

const pdf = await renderToBuffer(
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.row}>
        <Text style={styles.label}>Invoice</Text>
        <Text style={styles.label}>INV-0042</Text>
      </View>
    </Page>
  </Document>,
);
After: HTML elements and CSS
// takumi-pdf
import {  } from "@takumi-rs/helpers";
import {  } from "takumi-pdf";

const  = await (
  < ="flex justify-between text-gray-500" ={{ : (10 * 96) / 72 }}>
    <>Invoice</>
    <>INV-0042</>
  </>,
  { : "a4", : 64, : await (["Inter"]) },
);

Component map

@react-pdf/renderertakumi-pdf
<Document>none, since render() takes the tree
<Page size="A4">the size option
<View><div>
<Text><span>, <p>, or bare text
<Image src><img src> plus the images option
<Link src><a href>
<Svg> primitives<svg>, or an SVG through images
StyleSheet.createstyle objects or tw classes
Font.registerthe fonts option
renderToBufferrender() returns a Uint8Array
renderToStream, renderToFilewrite the returned bytes yourself
a fixed header or footer <View>the header and footer options
render={({ pageNumber, totalPages })}<PageNumber /> and <TotalPages />
the break propbreak-before: page
wrap={false}break-inside: avoid
orphans, widowsthe same CSS properties
minPresenceAheadnot supported
Font.registerHyphenationCallbacknot supported
Font.registerEmojiSourceextractEmojis, then prepareImages
<PDFViewer>, <PDFDownloadLink>render bytes, then provide a preview or download

Preserve the layout

Units are CSS px

react-pdf measures lengths in pt. Takumi measures them in CSS px at 96 dpi, so multiply every length by 96 / 72, about 1.333. A4 is 595 × 842 pt, or 794 × 1123 px. Unitless values such as flexGrow, opacity, and fontWeight carry over unchanged.

Flex direction defaults to row

react-pdf defaults every container to column. CSS defaults to row, so a stacked layout needs flex-direction: column written out.

Flex layout is opt-in

react-pdf's <View> is always a flex container. A plain HTML element is not, so a <div> that lays out children needs display: flex or display: grid. In Tailwind, write tw="flex flex-col".

Page bands

react-pdf repeats a band by marking a <View> inside the page as fixed. Takumi takes the band as a separate option and draws it in the margin:

Repeat page headers
import {  } from "takumi-pdf";
import { ,  } from "takumi-pdf/primitives";

const  = await (, {
  : (
    < ="flex w-full justify-center text-[10px] text-gray-500">
      Page < /> of < />
    </>
  ),
  : { : 48, : 72 },
});

The counter is a class on an element, not a render callback. See Headers & footers for counter styles and for sizing the margin to the band.

Assets load differently

The component map above shows where Font.register, <Image>, and Font.registerEmojiSource go.

Takumi does not use the 14 standard PDF fonts. Register every font your template uses.

See Fonts & images for the loaders.

Known gaps

Takumi has no equivalent for minPresenceAhead, hyphenation callbacks, or react-pdf's preview and download components. Render a Uint8Array and deliver it from your application. In a browser bundle, use the manual initialization entry. widows and orphans do work, as CSS properties, and Pagination covers them. For archival output and accessibility validation, see PDF/A & PDF/UA.

Last updated on