Invoices
Generate paginated PDF invoices with line items, totals, page numbers, and optional embedded XML.
Render line items and totals as a paged document. If your invoice format needs embedded XML, attach it and set the PDF/A and XMP options the format requires.
A plain invoice
Here, invoice is your invoice data and InvoiceDocument is your JSX template. Line items flow across pages, and the footer carries the page counter. measure() returns the footer's height, so you can reserve enough bottom margin:
import { } from "@takumi-rs/helpers";
import { , } from "takumi-pdf";
import { , } from "takumi-pdf/primitives";
const = (
< ="flex w-full justify-between px-12 text-[10px] text-[#6b7280]">
<>Invoice {.}</>
< ="flex">
Page < /> of < />
</>
</>
);
const = await (["Inter"]);
const { } = await (, { : "a4", });
const = await (< ={} />, {
: "a4",
: { : 48, : + 32, : 48, : 48 },
,
,
});For complete templates, see the invoice and receipt example.
Use break-inside: avoid, or break-inside-avoid in Tailwind, to keep a line item on one page:
import "takumi-pdf";
< ="flex break-inside-avoid gap-3 pt-3 text-xs">
< ="flex-1">{.}</>
< ="w-[100px] text-right">{.}</>
</>;Apply the same style to the totals block.
Electronic invoices
Factur-X and ZUGFeRD combine a readable PDF invoice with structured XML. Map what your profile requires to these options:
| The profile requires | The option |
|---|---|
| A PDF/A-3 container | pdfa: "3b" |
| The XML attached by name | attachments |
An fx: XMP block | metadata.xmp |
| A modification date per file | modificationDate |
| Embedded subset fonts | always on |
Each attachment's modificationDate falls back to metadata.creationDate, so one document date covers both. This example also validates against PDF/UA-1:
import { } from "takumi-pdf";
const = await (, {
: "en",
: "3b",
: "ua1",
: {
: "Invoice INV-2026-0042",
: "2026-08-06",
: [],
},
: [
{
: "factur-x.xml",
: ,
: "text/xml",
: "Factur-X 1.0 MINIMUM invoice data",
: "data",
},
],
});The renderer checks PDF conformance while writing. It does not check the invoice XML, tax rules, or whether a receiving system accepts the file.
Takumi does not build the invoice XML. Use a library for your profile, or write the elements the profile lists. The e-invoice example writes a MINIMUM profile by hand, along with the facturXmp schema used above.
Validating the result
Two validators cover the two halves. Both need Java.
veraPDF checks the container:
verapdf --flavour 3b --format text invoice.pdf
verapdf --flavour ua1 --format text invoice.pdfMustang checks the Factur-X half, both the XML and the packaging:
java -jar Mustang-CLI.jar --action validate --source invoice.pdfMustang finds the profile through the fx: XMP block. Takumi writes each value together with the schema description PDF/A requires, so the two cannot disagree. It does not check the values, so a wrong profile name shows up in Mustang, not at render time.
Accessible invoices
For PDF/UA-1 output, set tagged: "ua1", lang, and metadata.title. Then review the reading order and table structure yourself. See PDF/A and PDF/UA.
Reproducible bytes
Same content, resources, renderer version, and metadata.creationDate produce the same bytes. A new date changes the file even when the invoice looks the same.
Last updated on