How to Work with PDF Structure in TypeScript
This guide shows how to build document navigation and logical structure in PDF files with Aspose.PDF FOSS for TypeScript: a clickable table of contents on a page, a document-level bookmark outline, named destinations, and a tagged structure tree for accessibility. It requires Node.js 22 or later.
Step-by-Step Guide
Step 1: Install the Package
asposefoss/pdf is not yet published — build from source until it ships. See the project README for build instructions.
Verify the installation by importing the Document class in a new
TypeScript file — this line should resolve without error once the package
is installed:
import { Document } from '@asposefoss/pdf';Step 2: Import Required Classes
Import Document to open the file and OutlineItem for the bookmark
entries built in Step 4:
import { Document, OutlineItem } from '@asposefoss/pdf';Step 3: Add a Table of Contents
Page.AddTOC() takes an array of { title, page } entries, a bounding
rect, and style options; it draws dotted leaders and clickable links to
the target pages:
const page = doc.Pages[0];
page.AddTOC(
[
{ title: '1. Introduction', page: 2 },
{ title: '2. Methodology', page: 5 },
{ title: '3. Results', page: 9 },
],
[72, 160, 400, 600],
{ font: 'Helvetica', fontSize: 13, color: [0.1, 0.1, 0.15], rowGap: 18 },
);Step 4: Add Bookmarks
Document.SetOutlines() replaces the document’s bookmark panel with an
array of OutlineItem objects. Each item can carry a Dest (page
destination), styling (Color, Bold), and nested Children for a
collapsible tree:
const items: OutlineItem[] = [
{ Title: 'Sales', Dest: { name: 'section.sales' }, Open: true, Color: [0.1, 0.4, 0.1] },
{ Title: 'Appendix', Dest: { name: 'section.appendix' } },
];
doc.SetOutlines(items);Step 5: Read Outlines and Named Destinations
Document.GetOutlines() returns the current bookmark tree.
Document.GetNamedDestinations() returns every named destination
registered on the document — useful for verifying that every outline
target and TOC link actually resolves to a real page:
const destNames = new Set(doc.GetNamedDestinations().map((d) => d.name));
const walk = (nodes: OutlineItem[]): void => {
for (const item of nodes) {
if (item.Dest && 'name' in item.Dest) {
console.log(destNames.has(item.Dest.name), item.Title);
}
if (item.Children) walk(item.Children);
}
};
walk(doc.GetOutlines());Step 6: Build a Tagged Structure Tree
Document.GetStructTree() returns the existing structure tree (or null
if the document has not been tagged). StructTreeRoot.Append(tag) adds a
child element such as 'H2' or 'P' and returns a StructElement, and
StructElement.MarkContent(page, quad) associates that element with the
page content it describes:
function tagPage(doc: Document, page: Page, headingText: string): void {
const root = doc.GetStructTree();
if (!root) throw new Error('tagPage: the document is not tagged yet');
for (const block of page.GetStructuredText()) {
const text = block.text.trim();
if (text.length === 0) continue;
const el = root.Append(text.startsWith(headingText) ? 'H2' : 'P');
el.MarkContent(page, block.quad);
}
}Common Issues and Fixes
Document.GetStructTree() returns null. The document has not been
tagged yet — call Document.CreateStructTree() (or Document.AutoTag())
before hand-authoring elements with StructTreeRoot.Append() /
StructElement.MarkContent().
An outline item does not jump to the right page. OutlineItem.Dest
must name a destination that actually exists — cross-check
item.Dest.name against Document.GetNamedDestinations() before saving,
as shown in Step 5.
Page.AddTOC() entries point to the wrong page. page in each TOC
entry is the target page’s own page number — confirm it against
page.Number on the actual target Page, not an assumed array index.
Bookmarks disappear after a later Document.SetOutlines() call.
SetOutlines() replaces the entire bookmark tree — read the current tree
with Document.GetOutlines() first, modify the array, then pass the whole
array back if bookmarks are being added rather than replaced.
Frequently Asked Questions
Can a bookmark open already expanded?
Yes — set Open: true on the OutlineItem to have that node’s children
visible by default in the bookmark panel.
What is the difference between a bookmark and a named destination?
A bookmark (OutlineItem) is a visible entry in the navigation panel; a
named destination (Document.GetNamedDestinations() /
SetNamedDestination()) is an internal, reusable page target that a
bookmark, a TOC entry, or a link annotation can all point to by name.
Does tagging a document affect how it looks?
No — a structure tree (StructTreeRoot, StructElement) is a parallel
logical layer describing reading order and semantics; it does not change
the page’s visible content.
Can I nest bookmarks?
Yes — set Children on an OutlineItem to an array of further
OutlineItem objects to build a collapsible, multi-level tree.