Takumi

Pagination

Control where pages break with CSS.

Content lays out once at unbounded height. It then splits into pages. Unsplittable atoms never straddle a cut. These atoms include text lines, images, and transformed subtrees. A cut inside an atom moves to its top. This matches browser print fragmentation.

Break properties

import {  } from "takumi-pdf";

const  = await (
  <>
    < ={{ : "page" }}>Chapter two</>
    < ={{ : "avoid" }}>Keep this together.</>
  </>,
);
PropertyEffect
break-before: pageStarts the element on a new page.
break-after: pageStarts the following content on a new page.
break-inside: avoidKeeps the element on one page when it fits.
box-decoration-break: cloneRepeats borders and backgrounds on every page fragment.

A break-inside: avoid box taller than the page window cannot fit on a page. It stops participating in cut avoidance. Browsers apply the same rule.

Widows and orphans

A cut through a paragraph keeps at least orphans lines at the bottom of the page and widows lines at the top of the next. Both default to 2, like Chromium. Set them to 1 to allow lone lines:

import {  } from "takumi-pdf";

const  = await (
  < ={{ : 3, : 3 }}>
    A long report body wraps into many lines across the page boundary.
  </>,
);

Both properties inherit. When a paragraph is too short to satisfy both minimums, the orphans win, as in Chromium. A break that cannot keep the orphans moves the whole paragraph to the next page. A minimum that cannot fit the current page at all is dropped for that page, like break-inside: avoid on an oversized box.

Split decorations

A box that crosses a page break slices its border and background by default. Set box-decoration-break: clone to give each fragment complete decorations:

import {  } from "takumi-pdf";

const  = await (
  <
    ={{
      : "1px solid #d1d5db",
      : 8,
      : "clone",
    }}
  >
    Long content that continues on the next page.
  </>,
);

Watermarks

position: fixed paints a box on every page. The box lays out against the page area. It stays outside the content column.

import {  } from "takumi-pdf";

const  = await (
  <>
    {/* Centers the watermark inside each page area. */}
    <
      ={{
        : "fixed",
        : 0,
        : "flex",
        : "center",
        : "center",
      }}
    >
      < ={{ : 96, : "rgba(0,0,0,0.08)" }}>DRAFT</>
    </>
    <>Long content that continues on the next page.</>
  </>,
);

A transformed or filtered ancestor captures a fixed descendant. That descendant stays in flow and paginates with its ancestor.

A negative z-index paints the box under the content. A background on the root covers it, exactly as it does in a browser. Set the paper with backgroundColor instead, which paints under the box.

Last updated on

On this page