Add bookmarks and a table of contents
At a glance
Section titled “At a glance”This recipe adds bookmarks as a hierarchical document outline. The reader app shows these entries in its navigation sidebar, where they work as a clickable table of contents. An integer level controls the nesting. The recipe follows examples/12-bookmarks-and-toc.php.
ISO 32000-2 calls this structure the document outline: a tree of outline items that serves as a visual table of contents.
Install
Section titled “Install”composer require nextpdf/core:^3No optional extension is required. The bookmark API has been stable since 1.0.0 and runs on the 8.1–8.4 backport matrix.
Conceptual overview
Section titled “Conceptual overview”bookmark($title, $level, $y) adds one outline item bound to the current page. The binding uses the current Y position unless you pass an explicit Y value. $level sets the nesting depth: level 0 is a top-level chapter, level 1 is a section under the most recent level-0 item, and so on. The engine builds the outline tree for you. ISO 32000-2 chains items through Prev/Next at each level and nests them through First/Last, with the catalog’s Outlines entry as the root.
Each item carries a destination, so the reader jumps to the right page when you click the bookmark. ISO 32000-2 §12.3.2 states that destinations may be associated with outline items. The same call also feeds NextPDF’s table of contents builder, so the outline and rendered table of contents stay in sync.
API surface
Section titled “API surface”The API surface is generated from PHPDoc. This recipe relies on one method:
bookmark(string $title, int $level = 0, float $y = -1): static— adds an outline item at$levelbound to the current page.$y = -1uses the current cursor Y position. Pass a non-negative Y value to pin a precise destination.
Code sample — Quick start
Section titled “Code sample — Quick start”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();$doc->bookmark('Chapter 1', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 1', newLine: true);
$doc->bookmark('Section 1.1', level: 1); // nested under Chapter 1$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Section body.');
$doc->addPage();$doc->bookmark('Chapter 2', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 2', newLine: true);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/bookmarks.pdf');Code sample — Production
Section titled “Code sample — Production”This complete, harness-ready example honors NEXTPDF_COOKBOOK_OUTPUT and introduces no entropy of its own.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Bookmarks and Navigation');$doc->setPrintHeader(false);$doc->setPrintFooter(false);$doc->setAutoPageBreak(true, margin: 25);
// Chapter 1$doc->addPage();$doc->bookmark('Chapter 1: Introduction', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 1: Introduction', newLine: true);$doc->ln(3);
$doc->bookmark('What is NextPDF?', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'What is NextPDF?', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'NextPDF is a modern PDF 2.0 library for PHP 8.4+. ' . 'It generates standards-targeting documents with typography, ' . 'graphics, and signatures.');$doc->ln(5);
$doc->bookmark('Key Features', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'Key Features', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'HTML rendering, barcodes, PAdES signatures, ' . 'and a worker-safe architecture.');
// Chapter 2$doc->addPage();$doc->bookmark('Chapter 2: Getting Started', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 2: Getting Started', newLine: true);$doc->ln(3);
$doc->bookmark('Installation', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'Installation', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Install via Composer: composer require nextpdf/core');
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/bookmarks.pdf';$doc->save($out);
echo "Created bookmarks.pdf with a 2-level outline\n";Edge cases & gotchas
Section titled “Edge cases & gotchas”- Level skips. A jump from level 0 to level 2 with no level 1 in between can look malformed in some readers. Increase the level by at most one at a time.
- Bookmark before content. Call
bookmark()at the point where you want the destination. In most cases, place the call immediately before the heading. A call placed after the heading sets the destination slightly below it. - Explicit Y for precise destinations. With
$y = -1, the destination is the current cursor Y position. Pass an explicit Y value for a stable destination. For example, an explicit Y value pins the top of a section regardless of how much content precedes it. - Outline support is universal, but presentation varies. Readers may render the outline collapsed or expanded. This API cannot force an open or closed state per item.
Performance
Section titled “Performance”Each bookmark() call appends one outline item and one table of contents entry, which is O(1) work. The outline tree is finalized once, at save(). Hundreds of bookmarks stay well within the 2000 ms / 64 MB budget.
Security notes
Section titled “Security notes”Bookmark titles appear in the reader’s navigation interface. If a title includes user-controlled data, bound its length and sanitize it as you would any displayed string. This recipe performs no input parsing and no network access.
Conformance
Section titled “Conformance”| Statement | Spec | Clause | reference_id |
|---|---|---|---|
| The document outline is a tree of outline items acting as a visual table of contents. | ISO 32000-2 | §12.3.3 | |
Outline items chain through Prev/Next and nest through First/Last. | ISO 32000-2 | §12.3.3 | |
The outline dictionary is the catalog’s Outlines entry. | ISO 32000-2 | §7.7.2 | |
| Destinations may be associated with outline items. | ISO 32000-2 | §12.3.2 |
Reproducibility profile — structural. The trailer /ID and date atoms vary on each save, so the harness strips those atoms and compares the qpdf-normalized structure. This recipe describes how NextPDF produces that structure. It does not assert ISO 32000-2 conformance as a blanket claim.
Commercial context
Section titled “Commercial context”Not applicable. The document outline and table of contents are Core capabilities with no Premium gate.