Annotations
The toolbar includes highlight, freehand, rectangle, ellipse, line, arrow, and text tools. Annotations are viewer overlays only - they never get written into the PDF when you download or print. Persist changes with onAnnotationChange.
Built-in tools
- Highlight (color + opacity)
- Freehand ink (color, thickness, dotted)
- Shapes: rectangle, ellipse, line, arrow (fill, stroke, dotted)
- Free text (font, size, align, bold/italic/underline, background)
Select, move, resize, erase
Annotation tools sit on the main toolbar. Clicking a tool (or an existing annotation) opens a Canva-style style modal with color swatches, opacity, fill, thickness, and size. Choose Draw on page to place annotations; a floating chip reopens settings anytime.
- Drag the body to move
- Resize with 8 handles (4 corners + 4 edges), or width/height sliders on the format bar for highlights and rectangles
- Rectangles/ellipses support filled mode with separate fill color and fill opacity
- Click the red (x) or press Delete / Backspace to erase
- Double-click text annotations to re-edit content
- Escape clears selection and exits the active tool
Download excludes annotations
Download and print always export the original PDF bytes. Overlay annotations stay in the viewer (and in your app state if you persist them). This keeps the source file clean even after heavy markup sessions.
Persist annotations
Listen for changes and store the array. Restore later with the ref API or by rehydrating stored payloads via parseAnnotations:
import {
DocumentViewer,
serializeAnnotations,
parseAnnotations,
} from "lumipdf";
<DocumentViewer
source={{ kind: "url", url: "/contract.pdf" }}
onAnnotationChange={(annotations) => {
localStorage.setItem(
"contract-annotations",
serializeAnnotations(annotations),
);
}}
/>
// Restore
const annotations = parseAnnotations(
localStorage.getItem("contract-annotations"),
);
// ref.setAnnotations(annotations)Imperative control
import { useRef } from "react";
import { DocumentViewer, type PdfViewerRef } from "lumipdf";
const ref = useRef<PdfViewerRef>(null);
// ref.current?.addAnnotation(...)
// ref.current?.deleteAnnotation(id)
// ref.current?.clearAnnotations()
// ref.current?.setActiveTool("highlight")
// ref.current?.download() // original PDF, no annotations