Pagination
Control PDF page breaks, keep related content together, and set paragraph widows and orphans with CSS.
Content lays out at the width inside the margins, then flows across pages. Use CSS break properties to start chapters, keep related content together, and control how paragraphs split.
The content has no fixed height, so percentage heights do not resolve. Viewport units do. vh is the height of the page area inside the margins, as in print.
Break properties
import { } from "takumi-pdf";
const = await (
<>
< ={{ : "page" }}>Chapter two</>
< ={{ : "avoid" }}>Keep this together.</>
</>,
);| Property | Effect |
|---|---|
break-before: page | Starts the element on a new page. |
break-after: page | Starts the following content on a new page. |
break-inside: avoid | Keeps the element on one page when it fits. |
box-decoration-break: clone | Repeats borders and backgrounds on every page fragment. |
break-inside: avoid applies only when the box fits on a page. A taller box still splits.
A text line, an image, or a transformed subtree never splits unless it is taller than a page.
Full-page boxes
A 100vh box fills the page area, so the next box starts on the following page. Use it for a cover or any page laid out by hand:
import { } from "takumi-pdf";
const = await (
<>
< ={{ : "100vh", : "flex", : "flex-end" }}>
<>Annual report</>
</>
<>The report starts on page two.</>
</>,
{ : 0 },
);vw, vmin, and vmax resolve against the same page area. In the header and footer bands, viewport units resolve against the full page.
Widows and orphans
When a page break cuts a paragraph, at least orphans lines stay at the bottom of the page and at least widows lines move to the top of the next. Both default to 2, like Chromium. Set them to 1 to allow single lines:
import { } from "takumi-pdf";
const = await (
< ={{ : 3, : 3 }}>
A long report body wraps into many lines across the page boundary.
</>,
);- Both properties inherit.
- If a paragraph is too short to satisfy both,
orphanswins. - A paragraph moves to the next page when the current page cannot hold the required lines.
- A requirement taller than a full page is relaxed.
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.
</>,
);Repeated table headers and footers
A <thead> repeats at the top of each continuation page. A <tfoot> repeats below the last row on every page the table breaks across. Each section stays in one piece, with its spacing next to the body.
import { } from "takumi-pdf";
const = await (
<>
<>
<>
<>Name</>
<>Qty</>
</>
</>
<>{}</>
<>
<>
<>Total</>
<>{}</>
</>
</>
</>,
);A section repeats only when all of these hold:
- It has
break-inside: avoid.<thead>and<tfoot>set it by default, as in Chromium. - It is no taller than a quarter of the page area, matching Chromium.
- None of its cells has a
rowspanthat reaches into the body.
Page ranges
pageRanges keeps only the listed pages, like a print dialog. Each entry is a 1-based page number or an inclusive span:
import { } from "takumi-pdf";
const = await (<>{}</>, {
: [1, { : 4, : 8 }, { : 12 }],
});An unset from starts at the first page. An unset to runs to the last. The render fails if a range names page 0, runs backwards, or keeps no page.
Layout and page counters still run over the whole document. A kept page shows the numbers it has in full output, so page 4 of 12 still reads "Page 4 of 12". Links and outline entries that point at a dropped page are dropped with it.
Watermarks
A position: fixed box paints on every page. It lays out against the page area, outside the content flow.
import { } from "takumi-pdf";
const = await (
<>
<
={{
: "fixed",
: 0,
: "flex",
: "center",
: "center",
}}
>
< ={{ : 96, : "rgba(0,0,0,0.08)" }}>DRAFT</>
</>
<>Long content that continues on the next page.</>
</>,
);Keep the fixed box outside transformed or filtered ancestors. Such an ancestor contains the box, so the box paginates with it instead of repeating on every page.
To put the watermark behind content, give it a negative z-index. If the root background then covers it, set the page color with the backgroundColor option instead.
Last updated on