PDFPipe

Accessibility and structure / Heading levels

Heading levels in an accessible PDF

The /H1 to /H6 structure elements that give a document an outline, which is how a screen reader user skims a fifty page report without reading it.

Where this API stands

This API does not produce this standard, and there is no option that would. What follows is what the requirement actually is and where a rendered document stands against it. No /H1 to /H6 structure elements are written by this API. The material that matters is the heading elements in your markup, because they are what a tagger maps to structure types one for one, and because the mapping is mechanical only if the levels are already right. The specific failure this creates is a heading built out of presentation: a `<div class="section-title">` set in 18pt bold is a heading to every human reader and a paragraph to every tool, and no amount of downstream remediation can recover a rank that was never expressed.

What the standard requires

The requirements as a checker enforces them, rather than as a procurement document paraphrases them. A file satisfies all of these or it satisfies none of them.

  • Headings are /H1 through /H6 structure elements, in a hierarchy that does not skip a level going down.
  • A document has one /H1, which is the document title, and everything else sits under it.
  • A level is a statement about rank, not about size, so a subheading set in small type is still /H3 if that is where it sits in the outline.
  • Text that looks like a heading and is not one, such as a pull quote in large type, must not be a heading element, because it will appear in the outline and mislead.
  • PDF/UA treats a skipped level, such as /H2 followed directly by /H4, as a failure rather than a style issue.

Who asks for this

Accessibility audits, and also anyone who has watched a screen reader user work: the heading list is the primary navigation control for a long document, in the same way a sighted reader uses the visual hierarchy. A report with no headings is a report that has to be read from the beginning.

What to do about it

Fix the levels in the templates. Use `h1` once, then `h2` and `h3` in order, and style them with CSS rather than choosing the level by how large you want the text. Where a template is assembled from fragments, the level has to be a parameter rather than hard-coded, otherwise every included section starts at `h2` and the outline is flat. This is cheap now and it is the input every later step depends on.

How to check a file rather than assume

PAC 2024 lists the heading structure and flags skipped levels and missing /H1 explicitly. Acrobat's Tags panel shows the same hierarchy. Before any of that, the browser's own accessibility tree or an outline extension will show you the heading list for the source markup, which is faster and finds the same problems.

The mistake people make here

Choosing the level by size. Somebody wants a smaller subheading, uses `h4` instead of `h3` because the default styling is closer, and the outline now skips a level for a reason that is purely visual. Set the level by rank and set the size in CSS.

Frequently asked

Does this API produce Heading levels?

Not produced by this API. No /H1 to /H6 structure elements are written by this API. The material that matters is the heading elements in your markup, because they are what a tagger maps to structure types one for one, and because the mapping is mechanical only if the levels are already right. The specific failure this creates is a heading built out of presentation: a `<div class="section-title">` set in 18pt bold is a heading to every human reader and a paragraph to every tool, and no amount of downstream remediation can recover a rank that was never expressed.

Can I turn on the pdf_a option and be done?

No. The option writes an XMP packet declaring PDF/A-1b into the document catalogue, and the render response comes back carrying a warning that says in as many words that this is best-effort and that full conformance requires tagged structure and an embedded ICC profile. It is a claim written into the file, not a certificate earned by it, and a validator checks the claim against the bytes. Read the warning array in the response rather than taking the absence of an error as a pass.

Should I convert before rendering or after?

After, always. A conformance converter rewrites colour, embeds profiles, sets boxes and stamps metadata on a finished PDF. Trying to satisfy a conformance target from the source side means guessing at what the converter would have done, and the guesses that go wrong are expensive: flattening transparency you did not need to flatten changes what the page looks like.

Standards this one is confused with

The neighbours that matter are the ones people mistake for this, not the ones that sort next to it.

Conformance is decided after a file exists. Render the document, then check it, then convert only what the checker actually flags.