Takumi

Reports & statements

Long documents with chapters, bookmarks, and running bands.

Use page breaks for chapters, repeating headers for context, and bookmarks or a table of contents for navigation. The examples below combine these features for reports and account statements.

Chapters

break-before: page starts a section on a fresh page. break-inside: avoid keeps a figure with its caption:

import {  } from "takumi-pdf";

const  = await (
  <>
    < ={{ : "page" }}>
      <>Results</>
      < ={{ : "avoid" }}>
        < ={} ="Revenue by quarter" ={{ : 560, : 360 }} />
        <>Revenue by quarter</>
      </>
    </>
  </>,
);

widows and orphans keep a paragraph from splitting into lone lines, but they do not tie a heading to the text under it. Wrap the heading and its first paragraph in a break-inside: avoid box for that.

See Pagination for the full set of break properties.

Bookmarks

outline: true turns h1h6 into PDF bookmarks. A reader opens the sidebar and jumps between chapters. Nesting follows heading depth:

import {  } from "takumi-pdf";

const  = await (, {
  : true,
  : "en",
  : { : "Annual report 2026", : ["Acme Inc."] },
});

A table of contents is the same chapters as links, with the page each one starts on. <TargetPageNumber /> fills the page in:

import {  } from "takumi-pdf/primitives";

< ="flex flex-col gap-1 text-sm">
  {.(() => (
    < ={.} ={`#${.}`} ="flex items-baseline gap-2">
      <>{.}</>
      < ="flex-1 border-b border-dotted border-gray-300" />
      < ="w-8 shrink-0 text-right" />
    </>
  ))}
</>;

Each entry stays clickable, so the contents page works on screen as well as in print. Give the number a fixed width, or a two-digit page can rewrap the entry and renumber it. See Table of contents.

Running bands

A report header usually names the document and the period. A footer usually carries the page counter:

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

const  = await (, {
  : (
    < ="flex w-full justify-between px-12 text-[10px] text-gray-500">
      <>Annual report 2026</>
      <>Acme Inc.</>
    </>
  ),
  : (
    < ="flex w-full justify-center text-[10px] text-gray-500">
      < /> / < />
    </>
  ),
  : { : 64, : 64, : 48, : 48 },
});

Bands draw in the margin, so the margin has to be tall enough. Headers & footers shows how to derive the margin from the band.

Long tables

Use <table> markup. Rows split across pages, and column positions stay identical on every page. A <thead> that qualifies repeats at the top of each continuation page:

import "takumi-pdf";

< ="w-full text-xs">
  <>
    <>
      < ="text-left">Item</>
      < ="text-right">Amount</>
    </>
  </>
  <>
    {.(() => (
      < ={.}>
        <>{.}</>
        < ="text-right">{.}</>
      </>
    ))}
  </>
</>;

Tagged output maps the markup to Table, TR, TH and TD structure elements, so screen readers navigate by row and column. See Tables for layout coverage and PDF/A for the structure tree.

Batches

Statement runs render the same template thousands of times. Construct one PdfRenderer and keep it. Fonts register once and are reused for every document:

import {  } from "takumi-pdf";
import {  } from "@takumi-rs/helpers";

const  = new ();
const  = await (["Inter"]);

for (const  of ) {
  const  = await .(< ={} />, {  });
  await (., );
}

The renderer reuses registered fonts between documents. Keep tagged enabled when the output needs a structure tree.

Accessibility

Set tagged: "ua1" to request PDF/UA-1 validation. Supply the document language and title, then review heading order, tables, and chart descriptions. See PDF/A and PDF/UA.

Last updated on

On this page