Headers & footers
Add repeating PDF headers, footers, and page numbers, and measure the margins they need.
Pass JSX, an HTML string, or a node tree to header or footer. The band repeats in the top or bottom margin of every page, and automatic margins grow to fit it.
import { } from "takumi-pdf";
import { , } from "takumi-pdf/primitives";
const = await (, {
: (
< ="flex w-full justify-center text-[10px] text-gray-500">
Page < /> of < />
</>
),
});Pages that differ
pages overrides the header or footer on some pages. Each page looks up a band in this order:
firstorlastoddoreven- the top-level
headerorfooter
false leaves that band empty. Pages count from 1 over the whole document, before pageRanges drops any.
import { } from "takumi-pdf";
import { } from "takumi-pdf/primitives";
const = await (, {
: <>Acme Ltd</>,
: < />,
: {
: { : false },
: {
: (
<>
<>Thank you for your business.</>
<>Terms: net 30.</>
</>
),
},
},
});Automatic margins fit the tallest band on every page, so a taller last-page footer does not change where the other pages break. A one-page document is its own first and last page, and first wins.
Sizing the margin
margin defaults to "auto". The renderer measures the header and footer at full page width. Each automatic top or bottom margin is the band height plus a 20px inset, and at least 37.8px. Left and right margins are 37.8px.
A numeric margin overrides that side. Sides left out of the object stay automatic:
const margin = { top: 96 };A numeric margin that is too small lets the band overlap the body. To compute one, call measure() with the same page size and fonts as the render. It lays the band out at full page width with three-digit page counters. Add the 20px inset to the returned height.
import { } from "@takumi-rs/helpers";
import { , } from "takumi-pdf";
import { , } from "takumi-pdf/primitives";
const = await (["Inter"]);
const = (
< ={{ : "Inter", : 10, : "center" }}>
Page < /> of < />
</>
);
const { } = await (, { : "a4", });
const = await (, {
: "a4",
,
,
: { : + 20 },
});Passing viewport instead of a page size measures the tree as-is. Counter hooks stay empty.
Page counters
<PageNumber /> is the current page, counting from 1. <TotalPages /> is the number of pages in the document. Both take a format prop for a counter style, and pass className, style, and tw through.
Each primitive renders a <span> with a class hook. A node with the pageNumber or totalPages class receives the counter text in place of its children, so an empty <span /> is enough. Chromium's print templates use the same two class names. In HTML input, write the classes directly:
Page <span class="pageNumber"></span> of <span class="totalPages"></span>A node with both classes gets the page number.
Counters outside a band
Counters also work in document content. A position: fixed box repeats on every page, and a <PageNumber /> inside it shows each page's number:
<div style={{ position: "fixed", bottom: 24, left: 24, right: 24 }}>
Page <PageNumber /> of <TotalPages />
</div>A fixed box draws over the content, not in the margin, so leave room for it. Automatic margins fit only the header and footer.
In ordinary flow, <PageNumber /> shows the page the counter lands on. Its value depends on pagination, so the document lays out again after the numbers are filled in.
Counter styles
The format prop names a CSS @counter-style. On a class hook, add the style name as another class. The first supported name wins, unsupported names are ignored, and a counter without one uses decimal.
import { } from "takumi-pdf";
import { , } from "takumi-pdf/primitives";
const = await (, {
: (
< ={{ : 12 }}>
第 < ="trad-chinese-informal" /> 頁,共{" "}
< ="trad-chinese-informal" /> 頁
</>
),
});Numbers and numerals
| Style | Page 7 | Page 12 |
|---|---|---|
decimal (default) | 7 | 12 |
decimal-leading-zero | 07 | 12 |
lower-roman | vii | xii |
upper-roman | VII | XII |
cjk-decimal | 七 | 一二 |
trad-chinese-informal | 七 | 十二 |
cjk-ideographic | 七 | 十二 |
Blink defines cjk-ideographic as an extension of trad-chinese-informal, and takumi follows it. Both write numbers up to 9999 in words. Past that they fall back to cjk-decimal, so page 10000 formats as 一零零零零.
Alphabets
These styles count the way a spreadsheet names its columns. The letter after z is aa.
| Style | Page 12 |
|---|---|
lower-alpha, lower-latin | l |
upper-alpha, upper-latin | L |
lower-greek | μ |
hiragana | し |
katakana | シ |
Other digits
These styles write the decimal number in another script's digits.
| Style | Page 12 | Style | Page 12 |
|---|---|---|---|
arabic-indic | ١٢ | mongolian | ᠑᠒ |
bengali | ১২ | myanmar | ၁၂ |
cambodian | ១២ | oriya | ୧୨ |
devanagari | १२ | persian | ۱۲ |
gujarati | ૧૨ | tamil | ௧௨ |
gurmukhi | ੧੨ | telugu | ౧౨ |
kannada | ೧೨ | thai | ๑๒ |
khmer | ១២ | tibetan | ༡༢ |
lao | ໑໒ | urdu | ۱۲ |
malayalam | ൧൨ |
khmer and cambodian share their digits, as do persian and urdu.
Register a font that covers the digits of the style you pick. Latin fonts rarely include Thai or Tibetan digits.
Band height
A band with a counter is measured again with the real page count, up to three passes, and automatic margins use the final height. Give counters enough width that a longer page count does not wrap the band to a new line.
Last updated on