Structure

Structure

This page covers document navigation and logical structure: outlines (bookmarks), tables of contents, named destinations, and the tagged structure tree used for accessibility and reflow.


Outlines (Bookmarks)

Document.GetOutlines() returns the current outline tree as OutlineItem[] ([] when there is no /Outlines); Document.SetOutlines() replaces it — passing [] removes the outline entirely. Each OutlineItem has a Title, a Dest (a page number or a named destination), optional Children for nesting, and styling (Color, Bold, Italic, Open).

const items: OutlineItem[] = sections.map((s) => {
  const item: OutlineItem = { Title: s.title, Dest: { name: s.dest } };
  if (s.subtype === 'sales') {
    item.Open = true;
    item.Children = ['Pasta', 'Pizza', 'Antipasti']
      .map((cat) => ({ Title: cat, Dest: { name: s.dest } }));
  }
  return item;
});
doc.SetOutlines(items);

Table of Contents

Page.AddTOC() renders a list of TOCEntry objects — each with a title and a target page number — into a rectangle on a page, with wrapped titles, dot leaders, and right-aligned page labels. It returns an AddTOCResult reporting how many entries were drawn and, when the box is too small, the remainder that did not fit.

page.AddTOC(
  sections.map((s, i) => ({ title: `${i + 1}. ${s.title}`, page: s.page.Number })),
  [72, 160, 400, 400],
  { font: 'Helvetica', fontSize: 13, rowGap: 18 },
);

Named Destinations

Document.GetNamedDestinations() returns every named destination — merging the /Names /Dests name tree and the legacy /Dests dictionary — as { name, dest } pairs, where dest is a PageDest ({ page, view }). These are the same named targets an OutlineItem.Dest or a link annotation can reference by name instead of an explicit page number.

const destNames = new Set(doc.GetNamedDestinations().map((d) => d.name));
for (const { name, dest } of doc.GetNamedDestinations()) {
  console.log(name, '-> page', dest.page);
}

Tagged Structure Tree

Document.AutoTag() infers and authors a /StructTreeRoot from page layout — headings by font-size clustering, paragraphs by text blocks, tables by ruling geometry, and per-image /Figure vs. /Artifact decisions — and returns an AutoTagReport with counts for each element kind. Document.GetStructTree() reads back the resulting StructTreeRoot, or null when the document is untagged.

const report = doc.AutoTag({ lang: 'en-US', title: 'Quarterly Report', tables: true });
console.log(report.headings, report.paragraphs, report.tables, report.figures);

const tree = doc.GetStructTree();
console.log(tree ? tree.GetText() : '(no structure tree)');

Content added after AutoTag() has already run — a page filled in afterward, for example — is not covered by that pass and will not double-tag. StructTreeRoot.Append() and StructElement.MarkContent() are the manual authoring API alongside the heuristic one: Append() adds a child element of a given type, and MarkContent() marks a page region as belonging to that element.


Tips and Best Practices

  • Run Document.AutoTag() once, after page content is final — it does not re-tag content added afterward, so hand-tag anything added later with StructTreeRoot.Append() / StructElement.MarkContent().
  • Pass opts.title to AutoTag() — it also sets /ViewerPreferences /DisplayDocTitle, which PDF/UA requires alongside a document title.
  • An OutlineItem.Dest can target either an explicit page or a named destination ({ name: '...' }) — use named destinations when the target page number might shift as content changes.
  • Check AddTOCResult.remainder when auto-pagination is off — a table of contents box too small for every entry silently stops drawing rather than overflowing the box.

Common Issues

IssueCauseFix
Document.GetStructTree() returns nullThe document has not been taggedCall Document.AutoTag() or Document.CreateStructTree() first
An outline item’s link does not resolveIts Dest names a destination that does not exist in Document.GetNamedDestinations()Confirm the named destination exists, or use an explicit page Dest instead
Page.AddTOC() stops before the last sectionThe target rect is too small for every entry and autoPaginate is offEnlarge the rect, pass autoPaginate: true, or handle AddTOCResult.remainder
Content added after AutoTag() is missing from the structure treeAutoTag() only tags content present when it ranHand-tag the later content with StructTreeRoot.Append() / StructElement.MarkContent()

FAQ

How do I add bookmarks to a PDF?

Build an array of OutlineItem objects (Title, Dest, optional Children) and pass it to Document.SetOutlines().

Can a table of contents span multiple pages?

Yes — pass autoPaginate: true in Page.AddTOC()’s options, or check AddTOCResult.remainder and call AddTOC() again on a new page for whatever did not fit.

How do I make a PDF accessible (tagged)?

Call Document.AutoTag(), which infers headings, paragraphs, tables, and figures from page layout. For content added afterward, or where the heuristic result needs correction, use StructTreeRoot.Append() and StructElement.MarkContent() directly.

What is the difference between a page-number destination and a named destination?

A page-number destination (PageDest) targets an explicit 1-based page. A named destination (NamedDest) targets a name that a viewer resolves through the document’s own named-destination tables — useful when the target page might move.


API Reference Summary

Class/MethodDescription
Document.GetOutlines() / Document.SetOutlines()Read or replace the document outline (bookmark) tree
OutlineItemOne outline node: Title, Dest, optional Children
Page.AddTOC()Render a table of contents into a page rectangle
TOCEntry / AddTOCResultA TOC row’s data, and the outcome of drawing it
Document.GetNamedDestinations()List every named destination in the document
Document.AutoTag()Infer and author a tagged structure tree from page layout
Document.GetStructTree() / Document.CreateStructTree()Read or create the document’s StructTreeRoot
StructTreeRoot.Append() / StructElement.Append() / StructElement.MarkContent()Manually author or extend the structure tree

See Also