Skip to main content

Annotating

Annotations

Highlights, boxes, notes, ink, shapes and free text — with side notes, undo and PDF round trips.


Annotations.Root creates the AnnotationStore: the list (controlled or not), tools, colours, selection, undo/redo, keyboard shortcuts and PDF import/export. Layers render per page; floating parts and toolbars go anywhere inside.

Anatomy

<Annotations.Root bind:annotations author={{ name: 'Ada' }}>
	<!-- toolbar -->
	<Annotations.Tool tool="highlight" /> <Annotations.Color color="green" />
	<Annotations.Undo /> <Annotations.Redo />
	<!-- inside each Viewer.Page -->
	<Annotations.Layer />
	<Annotations.Margin />      <!-- side notes -->
	<Annotations.LineMarkers /> <!-- gutter bars -->
	<!-- anywhere inside -->
	<Annotations.SelectionMenu />
	<Annotations.Popover />
	<Annotations.HoverCard />
	<Annotations.List />
</Annotations.Root>
<Annotations.Root bind:annotations author={{ name: 'Ada' }}>
	<!-- toolbar -->
	<Annotations.Tool tool="highlight" /> <Annotations.Color color="green" />
	<Annotations.Undo /> <Annotations.Redo />
	<!-- inside each Viewer.Page -->
	<Annotations.Layer />
	<Annotations.Margin />      <!-- side notes -->
	<Annotations.LineMarkers /> <!-- gutter bars -->
	<!-- anywhere inside -->
	<Annotations.SelectionMenu />
	<Annotations.Popover />
	<Annotations.HoverCard />
	<Annotations.List />
</Annotations.Root>

Usage

  • Workflow: text selection opens the menu; every creation is pending (Enter keeps, Esc discards); tools are one-shot; editing needs a double-click. See Annotation workflow.
  • Note emoji: pass noteEmojis (e.g. defaultNoteEmojis: 💬 🤔 💡 🤯 🧐 🤨 😍 📌) and notes show an emoji instead of the icon. While the note tool is active, or notes are selected, keys 1–8 pick one (store.pickingNoteEmoji); bind:noteEmoji holds the active one and Annotations.NoteEmoji is its toolbar button.
  • Text box fonts: freetextFont sets the family of new text boxes ('Handwritten', 'Helvetica', 'Times', 'Courier'); the context menu’s Font submenu changes one. Typefaces come from --pdf-font-handwritten, --pdf-font-sans, --pdf-font-serif and --pdf-font-mono. See Annotation model.
  • Read-only: readonly, per-annotation locked, and foreign ('editable' · 'readonly' · 'hidden') for annotations found in the PDF.
  • Export: store.exportPdf(), toMarkdown(), toJSON(); importFromPdf loads annotations stored in the file. See PDF export & import.
  • Model: see Annotation model.

API reference

Annotations.Root

A provider: renders no element of its own.

Prop Type Default
annotations bindable The annotations. Bindable (or pass a value + onAnnotationsChange). Annotation[] []
onAnnotationsChange After each change (one call per undo step): persist here. (annotations: Annotation[], ops: AnnotationOp[]) => void —
tool bindable Active tool. Bindable. AnnotationTool 'select'
onToolChange (tool: AnnotationTool) => void —
color bindable Active palette key. Bindable. string 'yellow'
onColorChange (color: string) => void —
palette bindable Palette (bindable): custom colors picked by users are appended to it. PaletteColor[] defaultPalette
onPaletteChange (palette: PaletteColor[]) => void —
noteEmojis Emoji notes can show instead of the icon (e.g. `defaultNoteEmojis`): keys 1–8 pick one while the note tool is active. Default: none. readonly string[] —
noteEmoji bindable Active note emoji (one of `noteEmojis`; default the first). Bindable. string —
onNoteEmojiChange (emoji: string | undefined) => void —
annotationsVisible Show annotations (also `store.annotationsVisible`). boolean —
notesVisible Show side notes and gutter markers (also `store.notesVisible`). boolean —
colorFilter Only show these palette keys (null = all; also `store.colorFilter`). string[] | null —
author Author —
readonly boolean —
foreign Annotations that came from the PDF: 'editable' | 'readonly' | 'hidden'. ForeignPolicy —
stickyTools Keep the tool after creating (highlighter sessions). Default false: back to select (Shift keeps it once). boolean —
tools Tools (and text markups) offered. Default: all. Others get no shortcut or menu entry. readonly AnnotationTool[] —
selectOn How existing annotations are picked for editing. Default 'dblclick'. SelectOn —
editOnCreate Open the note of a new annotation for typing (Enter keeps, Esc discards). Default true. boolean —
inkSmoothing Pen stroke smoothing: 'smooth' (default), 'steady', 'pen' (variable width) or 'raw'. InkSmoothing —
freetextFont Font family of new text boxes: 'Handwritten', 'Helvetica' (sans, default), 'Times' (serif) or 'Courier' (mono). FreeTextFontFamily —
keymap Keyboard shortcuts, merged over `defaultKeymap`. Partial<Keymap> —
importFromPdf Load the annotations stored in the PDF (ours losslessly, others per `foreign`). boolean —
onImport (result: ImportResult) => void —
reanchor Re-anchor highlights to their quoted text when a document loads (e.g. a newer version of the paper). boolean —
store bindable The store (bind:store to use it outside). AnnotationStore —
Data attributes data-pdf-annotation-announcer

Annotations.Layer

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
noteIcon Custom note icon. Snippet<[AnnotationSnippetProps]> —
areaLabel Custom label chip for area boxes. Snippet<[AnnotationSnippetProps]> —
Data attributes data-activedata-drawingdata-emojidata-partdata-pdf-annotation-focusdata-pdf-annotation-labeldata-pdf-annotation-layerdata-pdf-annotation-notedata-pdf-annotation-overlaydata-pdf-annotation-svgdata-pdf-annotation-uidata-pdf-draw-surfacedata-selecteddata-themedata-tooldata-underlay

Annotations.SelectionMenu

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
forceMount Keep rendering `child` while closed (with `open: false`) so you can run exit transitions. boolean false
onOpenChange (open: boolean) => void —
placement FloatingPlacement 'top'
Snippet prop Type
open boolean
text string
markup (kind?: TextMarkupKind, color?: string) => Annotation[]
comment () => void
copy () => void
close () => void
Data attributes data-colordata-force-mountdata-partdata-pdf-annotation-uidata-pdf-selection-menudata-state

Annotations.Popover

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
forceMount Keep rendering `child` while closed (with `open: false`) so you can run exit transitions. boolean false
onOpenChange (open: boolean) => void —
placement FloatingPlacement 'bottom'
showQuote Repeat the quoted text inside the popover. Default false (it is right there on the page). boolean false
Snippet prop Type
open boolean
remove () => void
close () => void
annotation Annotation
selected boolean
hovered boolean
editable boolean
color CSS color for the current page theme. string
emoji A note's emoji (shown instead of its icon), if any. string | undefined
Data attributes data-activedata-force-mountdata-kinddata-partdata-pdf-annotation-popoverdata-pendingdata-state

Annotations.HoverCard

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
forceMount Keep rendering `child` while closed (with `open: false`) so you can run exit transitions. boolean false
onOpenChange (open: boolean) => void —
placement FloatingPlacement 'top'
delay number 250
Snippet prop Type
annotation Annotation
selected boolean
hovered boolean
editable boolean
color CSS color for the current page theme. string
emoji A note's emoji (shown instead of its icon), if any. string | undefined
open boolean
Data attributes data-force-mountdata-partdata-pdf-annotation-hover-carddata-state

Annotations.Margin

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
filter Which annotations get a side note. Default: those with a comment or a label. (a: Annotation) => boolean defaultFilter
gap Gap between notes (px). Default 8. number 8
side PageSide 'right'
minWidth Notes never overflow the view: they shrink to the room beside the page (`viewer.sideRoom`) plus the page's blank margin (they cover it, never its text, when the view is tight), and below this width (px) turn into compact markers that show the note on hover and open it on click. Default 140. number 140
edge Space (px) notes keep from the edge of the view, e.g. to clear a `Toc.Rail` laid over it. Default 8. number 8
layout Force a layout instead of adapting to the room. Default 'auto'. MarginLayout 'auto'
note Snippet<[MarginNoteSnippetProps]> —
Data attributes data-hovereddata-layoutdata-partdata-pdf-annotation-margindata-pdf-annotation-uidata-pdf-margin-markerdata-pdf-margin-notedata-placementdata-selecteddata-side

Annotations.LineMarkers

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
markers 'notes' (default): annotations with a note or label; 'all': every annotation. 'notes' | 'all' 'notes'
filter Custom filter (overrides `markers`). (a: Annotation) => boolean —
side PageSide 'left'
Data attributes data-hovereddata-lanedata-pdf-annotation-uidata-pdf-line-markerdata-pdf-line-markersdata-selecteddata-side

Annotations.List

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
filter (a: Annotation) => boolean —
item Snippet<[ListItemSnippetProps]> —
empty Snippet —
Snippet prop Type
annotations Annotation[]
Data attributes data-kinddata-partdata-pdf-annotation-listdata-pdf-annotation-list-itemdata-selected

Annotations.Crop

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
annotation required Annotation —
width number 240
padding number 6
Data attributes data-pdf-annotation-crop

Annotations.Comment

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
annotation required Annotation —
placeholder string —
autofocus boolean false
mode 'auto' (default): textarea while editing, rendered Markdown + maths otherwise. CommentMode 'auto'
Data attributes data-modedata-partdata-pdf-annotation-commentdata-pdf-annotation-ui

Annotations.Markdown

A provider: renders no element of its own.

Annotations.Tool

Renders a <button> (or your element via child) and accepts its HTML attributes.

Prop Type Default
tool required AnnotationTool —
Snippet prop Type
active boolean
Data attributes data-activedata-pdf-annotation-tool

Annotations.Color

Renders a <button> (or your element via child) and accepts its HTML attributes.

Prop Type Default
color required string —
Snippet prop Type
active boolean
swatch PaletteColor | undefined
Data attributes data-activedata-pdf-annotation-color

Annotations.NoteEmoji

Renders a <button> (or your element via child) and accepts its HTML attributes.

Prop Type Default
emoji required string —
Snippet prop Type
active boolean
Data attributes data-activedata-pdf-annotation-note-emoji

Annotations.Undo

Renders a <button> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
disabled boolean

Annotations.Redo

Renders a <button> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
disabled boolean