PDF/A
Archival output that validators accept
Render a PDF/A document with pdfa.
import { } from "takumi-pdf";
const = await (, {
: "3b",
});Conforming output includes an sRGB output intent and XMP metadata. Fonts are always embedded and subset, with or without PDF/A.
Levels
| Level | PDF version | What it adds |
|---|---|---|
"2b" | PDF 1.7 | Basic conformance. |
"2u" | PDF 1.7 | 2b plus guaranteed Unicode mapping. |
"2a" | PDF 1.7 | 2u plus a tagged structure tree. |
"3b" | PDF 1.7 | 2b plus arbitrary file attachments. |
"3u" | PDF 1.7 | 2u plus arbitrary file attachments. |
"3a" | PDF 1.7 | 3u plus a tagged structure tree. |
"4" | PDF 2.0 | The PDF 2.0 revision of the standard. |
"4f" | PDF 2.0 | 4 plus arbitrary file attachments. |
The u levels add no output cost. Takumi always writes ToUnicode maps.
PDF/A-3 and PDF/A-4f allow arbitrary file attachments. ZUGFeRD and Factur-X electronic invoices expect "3b". See Attachments.
PDF/A-1 is not offered. It prohibits transparency.
Validation runs during rendering. When a document cannot conform, the render fails with the violated rule instead of writing a broken file.
Every level, and PDF/UA-1, passes veraPDF, the reference validator.
Tagged output
tagged defaults to true. Tagged output mirrors Chromium's print-to-PDF.
Set tagged: "ua1" to also validate against PDF/UA-1:
import { } from "takumi-pdf";
const = await (, {
: "2a",
: "ua1",
: "en",
: {
: "Annual report",
: "2026-08-06",
},
});The structure tree comes from the HTML semantics:
| HTML | |
|---|---|
h1–h6 | Hn with the heading text as title |
p, bare text | P |
img | Figure with the alt text |
img with alt="" | artifact (decorative, no element) |
figure, figcaption | one Figure holding a Caption |
a | Link, holding the link annotation |
ul, ol, li | L, LI, LBody |
strong, em, code | Strong, Em, Code |
| page headers and footers | artifacts |
Heading levels come from nesting, not the tag name. A document that starts with h2 gets an H1. A jump from h1 to h4 becomes H1 then H2. PDF/UA rejects a sequence that skips a level or starts below H1. HTML written for visual styling does this all the time.
Tables are missing from that list. <table> markup is not supported. Flex-row tables omit Table, TR and TH elements. Screen readers cannot navigate them by row or column. The file still passes PDF/UA-1, because the validator only checks the tags that are there.
Set tagged: false to skip the tree when file size matters more than accessibility.
PDF/UA-2
tagged: "ua2" validates against PDF/UA-2 instead. The standard is PDF 2.0 only, so it pairs with pdfa: "4", pdfa: "4f", or plain PDF.
import { } from "takumi-pdf";
const = await (, {
: "4",
: "ua2",
: "en",
: {
: "Annual report",
: "2026-08-08",
},
});Links and outline entries target structure elements, not page positions. Reading order survives when a viewer follows one.
What combines with what
Invalid combinations are TypeScript type errors. PDF/UA-1 uses PDF 1.7. PDF/A-4 and PDF/UA-2 use PDF 2.0. The two generations never mix.
pdfa | tagged | attachments |
|---|---|---|
| unset | false, true, "ua1", "ua2" | yes |
2b, 2u | false, true, "ua1" | no |
2a | true, "ua1" | no |
3b, 3u | false, true, "ua1" | yes |
3a | true, "ua1" | yes |
4 | false, true, "ua2" | no |
4f | false, true, "ua2" | yes |
See Attachments.
Validators require inputs the renderer cannot supply:
langis the document language. A-levels and PDF/UA require it. PDF/UA-2 fails the render without it. A passage in another language needs its ownlangattribute.metadata.titleis required by PDF/UA.metadata.creationDateis required by thealevels. Use UTC"YYYY-MM-DD"or"YYYY-MM-DDTHH:MM:SS". A fixed date keeps output byte-identical across runs.
PDF/UA also requires a document outline. Takumi generates it from headings.
Last updated on