EmbedPDF

Annotations

The PDFViewer includes a powerful annotation system that supports highlights, ink drawings, shapes, and more. While the built-in toolbar provides a UI for these tools, you can also control them programmatically.

Configuration

You can configure annotation defaults like the author name using the annotation config object.

<PDFViewer config={{ annotation: { annotationAuthor: 'John Doe', } }} />

Programmatic Control

You can control the active tool and manage annotations programmatically.

Tools:
Log: Ready

Setting the Active Tool

Use setActiveTool to switch between tools. Pass null to switch back to the default selection cursor.

import { AnnotationPlugin } from '@embedpdf/react-pdf-viewer'; const registry = await viewerRef.current?.registry; const annotationPlugin = registry.getPlugin<AnnotationPlugin>('annotation')?.provides(); // Activate Highlighter annotationPlugin?.setActiveTool('highlight'); // Activate Pen (Ink) annotationPlugin?.setActiveTool('ink'); // Deactivate tool (switch to selection mode) annotationPlugin?.setActiveTool(null);

Common Tool IDs

ToolIDDescription
Highlight'highlight'Text highlighter
Underline'underline'Text underline
Ink (Pen)'ink'Freehand drawing
Rectangle'square'Square/Rectangle shape
Circle'circle'Circle/Ellipse shape
Text'freeText'Free text box
Note'text'Sticky note

Listening for Changes

You can listen for annotation events (creation, deletion, updates) to sync with a backend or update your UI.

const registry = await viewerRef.current?.registry; const annotationPlugin = registry.getPlugin('annotation').provides(); // Listen for creation, updates, and deletion annotationPlugin.onAnnotationEvent((event) => { const { type, annotation, pageIndex } = event; if (type === 'create') { console.log('Created annotation:', annotation.id); // e.g. save to backend } else if (type === 'delete') { console.log('Deleted annotation:', annotation.id); } }); // Listen for tool changes annotationPlugin.onActiveToolChange(({ tool }) => { console.log('Active tool:', tool ? tool.name : 'Selection'); });

Importing and Exporting Annotations

You can export all annotations from a document and re-import them later. This is useful for saving annotation state to a backend or transferring annotations between sessions.

Tools
Import / Export

Exporting Annotations

exportAnnotations() returns a Task that resolves to an array of AnnotationTransferItem objects. Each item contains the annotation object and, for stamps, a ctx with the appearance data as an ArrayBuffer.

import { AnnotationPlugin, type AnnotationTransferItem } from '@embedpdf/react-pdf-viewer'; const registry = await viewerRef.current?.registry; const api = registry?.getPlugin<AnnotationPlugin>('annotation')?.provides(); api?.exportAnnotations().wait( (items: AnnotationTransferItem[]) => { // items can be serialized and stored console.log(`Exported ${items.length} annotations`); }, (error) => console.error('Export failed', error), );

Importing Annotations

importAnnotations() accepts the same AnnotationTransferItem[] format returned by exportAnnotations(), making the round-trip seamless.

api?.importAnnotations(savedItems);

For stamps, the ctx.data field accepts a raw ArrayBuffer containing PNG, JPEG, or PDF data — the engine detects the format automatically via magic bytes.

const pngBuffer = await fetch('/my-stamp.png').then(r => r.arrayBuffer()); api?.importAnnotations([ { annotation: { type: PdfAnnotationSubtype.STAMP, rect: { origin: { x: 100, y: 200 }, size: { width: 50, height: 50 } }, // ... other annotation properties }, ctx: { data: pngBuffer }, }, ]);

Adding Custom Stamp Tools

You can register custom stamp tools that place images with a single click. Access the annotation API after the viewer initializes:

import { AnnotationPlugin, type AnnotationTool, PdfAnnotationSubtype, type PdfStampAnnoObject, } from '@embedpdf/react-pdf-viewer'; const registry = await viewerRef.current?.registry; const api = registry?.getPlugin<AnnotationPlugin>('annotation')?.provides(); api?.addTool<AnnotationTool<PdfStampAnnoObject>>({ id: 'stampCheckmark', name: 'Checkmark', interaction: { exclusive: true, cursor: 'crosshair' }, matchScore: () => 0, defaults: { type: PdfAnnotationSubtype.STAMP, imageSrc: '/circle-checkmark.png', imageSize: { width: 30, height: 30 }, }, behavior: { showGhost: true, deactivateToolAfterCreate: true, selectAfterCreate: true, }, });
Last updated on April 3, 2026

Need Help?

Join our community for support, discussions, and to contribute to EmbedPDF's development.