Navigation: annotations, links, outlines, actions, and attachments
At a glance
Section titled “At a glance”The Navigation module builds the Portable Document Format (PDF) interactive layer. It covers annotations, link and Uniform Resource Locator (URL) annotations, the document outline (bookmarks), the table of contents, actions and trigger chains, page transitions, and embedded-file attachments with their associated-file relationships.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”ISO 32000-2 §12 defines a PDF document’s interactive features: annotations, actions, destinations, and the document outline. This module encodes that layer for the engine. Manager classes collect intent; value objects carry the data those managers emit.
AnnotationManager is the broadest entry point. It adds text, free-text, line,
square, circle, polygon, polyline, ink, and text-markup annotations
(highlight and underline). It is hardened for hostile input: an unknown
annotation subtype falls back to a safe default, an icon name that is not a
valid PDF name token is replaced, and text-markup QuadPoints must arrive as a
multiple of eight floats or they are dropped. These checks are PDF-injection
defenses, not validation conveniences. LinkManager handles internal links,
named destinations, and URL annotations. It pre-allocates annotation objects so
the Writer can reference them before serialization.
BookmarkManager and TocBuilder build the navigation hierarchy. The document
outline is the bookmark tree a viewer shows in its sidebar. TocBuilder
renders an on-page table of contents and can use FontMetrics for leader/width
layout. OutlineAutoGenerator derives an outline from document structure.
The Action hierarchy under NextPDF\Navigation\Action models trigger-driven
behavior: GoTo (remote and embedded), launch, named, hide, reset/submit form,
and set optional-content state. The §13 screen-annotation rendition action is
deferred; it is future work and is not yet wired. Do not rely on it as a
supported action. Action::withNext() builds the action chain that runs for a
single trigger event. PageTransition models a
presentation transition. FileAttachment embeds a file from a path or a byte
string and tags it with an AFRelationship (the associated-file relationship
enum). It returns a FileAttachmentResult and writes through
writeAttachments(). The core managers are @since 1.0.0. The action
hierarchy is @since 2.1.0. The FileAttachment constructor and
AFRelationship arrived at @since 1.8.0 / @since 1.1.0.
API surface
Section titled “API surface”| Class | Key members | Role |
|---|---|---|
AnnotationManager | addAnnotation(), addFreeText(), addLine(), addSquare(), addCircle(), addPolygon(), addInk(), addHighlight(), addUnderline() | Annotation builder with injection-safe inputs (@since 1.0.0) |
LinkManager | addLink(), setLink(), setDestination(), addLinkAnnotation(), addUrlAnnotation(), preallocateAnnotationObjects() | Internal links, named destinations, URL annotations (@since 1.0.0) |
BookmarkManager | addBookmark(), hasBookmarks(), write() | Document outline (bookmark) tree (@since 1.0.0) |
TocBuilder | addEntry(), hasEntries(), render(), getEntries() | On-page table of contents (@since 1.0.0) |
Action (interface) | subtype(), toDictionary(), withNext(), nextChain() | Trigger action + action chain (@since 2.1.0) |
PageTransition | toDict(), toInlineDict() | Presentation page transition (@since 1.2.0) |
FileAttachment | embedFile(), embedFileFromString(), hasAttachments(), getCount(), writeAttachments() | Embedded-file attachments (@since 1.0.0) |
AFRelationship (enum) | toPdfName() | Associated-file relationship (@since 1.1.0) |
AnnotationFlags | with(), without(), has(), toInt() | Immutable annotation flag set (@since 1.2.0) |
Run composer docs:generate-api-php -- --module=Navigation to generate the
full PHPDoc table.
Code sample — Quick start
Section titled “Code sample — Quick start”examples/12-bookmarks-and-toc.php builds the document outline through the
high-level facade that wraps BookmarkManager. To use the manager directly:
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Navigation\BookmarkManager;
$bookmarks = new BookmarkManager();$bookmarks->addBookmark(title: 'Chapter 1', level: 0, pageIndex: 0);$bookmarks->addBookmark(title: '1.1 Overview', level: 1, pageIndex: 0);$bookmarks->addBookmark(title: 'Chapter 2', level: 0, pageIndex: 4);
if ($bookmarks->hasBookmarks()) { // The Writer calls $bookmarks->write(...) during catalog serialization.}Code sample — Production
Section titled “Code sample — Production”Embed an attachment with an explicit associated-file relationship, then check the result before finalizing the document.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Navigation\AFRelationship;use NextPDF\Navigation\FileAttachment;
$attachments = new FileAttachment();
$attachments->embedFile( path: '/srv/invoices/INV-2026-0042.xml', description: 'Structured invoice source (Factur-X)', afRelationship: AFRelationship::Source,);
if ($attachments->hasAttachments()) { // writeAttachments() is invoked by the Writer with a live ObjectRegistry; // getCount() lets the application assert the expected attachment count. assert($attachments->getCount() === 1);}Edge cases & gotchas
Section titled “Edge cases & gotchas”AnnotationManagersilently normalizes hostile input: an invalid subtype becomes the default, a non-name icon becomes the default icon, and malformedQuadPointsare dropped. The annotation is still produced; validate inputs upstream if you need them honored exactly.LinkManager::preallocateAnnotationObjects()must run before the Writer serializes references, or link targets resolve to nothing.Action::withNext()returns a new action with the chain attached; the interface supports immutable chaining, not in-place mutation.FileAttachment::writeAttachments()requires a liveObjectRegistryfrom the Writer. Called in isolation, the manager accumulates intent but writes nothing until the Writer drives it.AnnotationFlagsis an immutable flag set.with()/without()return a new instance; the original is unchanged.
Performance
Section titled “Performance”Annotation, link, and bookmark accumulation is O(n) in the number of items and
performs no reflow. Embedded-file attachment cost is dominated by the embedded
byte size, not by manager overhead. The default reference workload stays inside
the 1500 ms wall / 64 MB peak budget. The reproducibility profile is
structural: object numbers and the trailer /ID differ between runs. Two
documents with the same navigation intent are structurally equal but not
byte-identical.
Security notes
Section titled “Security notes”AnnotationManager treats annotation subtype, icon, and QuadPoints as
untrusted. It validates each value against an allow-list or pattern and
replaces a bad value instead of writing it through. This closes a PDF
name-injection vector. LinkManager::addUrlAnnotation() encodes a URL into a
link action. The URL remains the consumer’s trust boundary: a hostile URL can
still be valid, so sanitize destinations before adding them. FileAttachment
embeds arbitrary bytes. Bound the embedded size, and treat any user-supplied
attachment source as untrusted. See the engine threat model in
/modules/core/security/.
Conformance
Section titled “Conformance”The structures this module emits follow ISO 32000-2 §12 for annotations,
actions, destinations, and the document-outline hierarchy. Per-feature clause
references (annotation icons §12.5.6.4, text-markup QuadPoints §12.5.6.10,
actions §12.6) are documented inline in
src/Navigation/ and exercised by tests/Unit/Navigation/. These are
implementation facts, not a statement of end-to-end PDF 2.0 conformance.
Full-document conformance is validated by the oracle and golden suites
described in /modules/core/conformance/.
See also
Section titled “See also”- Document module
- Multimedia module — the rendition objects a rendition action plays.
- Writer module — serializes the navigation structures.
- Conformance overview
- Engine security model