Annotation Plugin
The Annotation Plugin provides a comprehensive framework for adding, editing, and managing annotations within a PDF document. It supports a wide range of common annotation types, including text markups (highlight, underline), free-hand drawings (ink), shapes (squares, circles), and more.
The plugin is built on an extensible “Tool” system, allowing you to define and customize different annotation behaviors and appearances.
Installation
This plugin has several dependencies that must be installed to handle user interactions and manage state. The history
plugin is optional but recommended for undo/redo functionality.
npm install @embedpdf/plugin-annotation @embedpdf/plugin-interaction-manager @embedpdf/plugin-selection @embedpdf/plugin-history
Registration
Import AnnotationPluginPackage
and its dependencies. It is crucial to register the dependencies before the annotation plugin itself.
import { createPluginRegistration } from '@embedpdf/core'
import { EmbedPDF } from '@embedpdf/core/vue'
// ... other imports
import { InteractionManagerPluginPackage } from '@embedpdf/plugin-interaction-manager/vue'
import { SelectionPluginPackage } from '@embedpdf/plugin-selection/vue'
import { HistoryPluginPackage } from '@embedpdf/plugin-history/vue'
import { AnnotationPluginPackage } from '@embedpdf/plugin-annotation/vue'
const plugins = [
// ... other essential plugins
createPluginRegistration(LoaderPluginPackage, { /* ... */ }),
createPluginRegistration(RenderPluginPackage),
// Register dependencies first
createPluginRegistration(InteractionManagerPluginPackage),
createPluginRegistration(SelectionPluginPackage),
createPluginRegistration(HistoryPluginPackage),
// Register and configure the annotation plugin
createPluginRegistration(AnnotationPluginPackage, {
// Optional: Set the author name for created annotations
annotationAuthor: 'Jane Doe',
}),
]
Usage
The plugin works by combining a UI component to render the annotations with a composable to manage the annotation tools and state.
1. The <AnnotationLayer />
Component
This component is responsible for rendering all annotations and handling user interactions like creating, selecting, moving, and resizing. It must be placed inside the <Scroller />
’s default slot and wrapped by a <PagePointerProvider>
to correctly process pointer events.
<script setup lang="ts">
import { PagePointerProvider } from '@embedpdf/plugin-interaction-manager/vue';
import { AnnotationLayer } from '@embedpdf/plugin-annotation/vue';
</script>
<template>
<Scroller>
<template #default="{ page }">
<PagePointerProvider
:page-index="page.pageIndex"
:page-width="page.width"
:page-height="page.height"
:rotation="page.rotation"
:scale="page.scale"
>
<RenderLayer :page-index="page.pageIndex" :scale="page.scale" style="pointer-events: none" />
<SelectionLayer :page-index="page.pageIndex" :scale="page.scale" style="pointer-events: none" />
<AnnotationLayer
:page-index="page.pageIndex"
:scale="page.scale"
:page-width="page.width"
:page-height="page.height"
:rotation="page.rotation"
/>
</PagePointerProvider>
</template>
</Scroller>
</template>
2. Building an Annotation Toolbar
The useAnnotationCapability
composable provides all the necessary methods to control the plugin. You can build a toolbar that allows users to select an “active tool” (like a pen or highlighter) and perform actions like deleting a selected annotation.
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { useAnnotationCapability } from '@embedpdf/plugin-annotation/vue';
const { provides: annotationApi } = useAnnotationCapability();
const activeTool = ref<string | null>(null);
const canDelete = ref(false);
let unsub1: () => void;
let unsub2: () => void;
onMounted(() => {
if (!annotationApi.value) return;
unsub1 = annotationApi.value.onActiveToolChange(tool => (activeTool.value = tool?.id ?? null));
unsub2 = annotationApi.value.onStateChange(state => (canDelete.value = !!state.selectedUid));
});
onUnmounted(() => {
unsub1?.();
unsub2?.();
});
const setActiveTool = (toolId: string) => {
annotationApi.value?.setActiveTool(activeTool.value === toolId ? null : toolId);
}
</script>
<template>
<div>
<button @click="setActiveTool('highlight')">Highlighter</button>
<button @click="setActiveTool('ink')">Pen</button>
</div>
</template>
3. Creating Custom Tools
You can extend the plugin’s functionality by adding your own tools. For example, you could create a custom image stamp. This is done by calling addTool
on the plugin’s capability, often within the @initialized
event handler of the <EmbedPDF>
component.
<script setup lang="ts">
import type { PluginRegistry } from '@embedpdf/core';
import { AnnotationPlugin, type AnnotationTool } from '@embedpdf/plugin-annotation/vue';
import { PdfAnnotationSubtype, type PdfStampAnnoObject } from '@embedpdf/models';
const handleInitialized = (registry: PluginRegistry) => {
const annotationApi = registry.getPlugin<AnnotationPlugin>('annotation')?.provides();
annotationApi?.addTool<AnnotationTool<PdfStampAnnoObject>>({
id: 'stampApproved',
name: 'Approved Stamp',
interaction: { exclusive: false, cursor: 'copy' },
matchScore: () => 0, // Doesn't match existing annotations
defaults: {
type: PdfAnnotationSubtype.STAMP,
imageSrc: '/images/approved-stamp.png', // URL to your stamp image
},
});
};
</script>
<template>
<EmbedPDF :engine="engine" :plugins="plugins" @initialized="handleInitialized">
</EmbedPDF>
</template>
Live Example
The example below includes a toolbar for selecting different annotation tools (highlight, ink pen, square) and a delete button that becomes active when an annotation is selected.
API Reference
Configuration (AnnotationPluginConfig
)
Option | Type | Description |
---|---|---|
annotationAuthor | string | Sets the author name for all created annotations. Default: 'Guest' |
autoCommit | boolean | If true , annotation changes are automatically saved to the engine. Default: true |
tools | AnnotationTool[] | An array of custom annotation tools to add or override default tools. |
colorPresets | string[] | A list of hex color strings to be used in a color picker UI. |
deactivateToolAfterCreate | boolean | If true , the active tool is deselected after an annotation is created. Default: false |
selectAfterCreate | boolean | If true , a newly created annotation is automatically selected. Default: true |
Component: <AnnotationLayer />
The primary component for rendering and interacting with annotations.
Prop | Type | Description |
---|---|---|
pageIndex | number | (Required) The page index this layer corresponds to. |
scale | number | (Required) The current zoom scale of the page. |
rotation | number | (Required) The current rotation of the page. |
pageWidth | number | (Required) The unscaled width of the PDF page. |
pageHeight | number | (Required) The unscaled height of the PDF page. |
selectionOutlineColor | string | The color of the outline around a selected annotation. Default: '#007ACC' |
Scoped Slot: selection-menu
The <AnnotationLayer>
provides a scoped slot to render a custom menu when an annotation is selected.
Prop | Type | Description |
---|---|---|
item | RedactionItem | The selected annotation data. |
selected | boolean | true if an annotation is currently selected. |
menuWrapperProps | object | Vue props to bind to your menu’s wrapper element for positioning. |
rect | Rect | The bounding box of the selected annotation. |
Composable: useAnnotationCapability()
Connects your components to the annotation plugin’s state and methods.
Returns
Property | Type | Description |
---|---|---|
provides | Ref<AnnotationCapability | null> | A ref object with methods to control the plugin, or null if not ready. |
AnnotationCapability
Methods
A selection of key methods available on the provides.value
object:
Method | Description |
---|---|
setActiveTool(toolId) | Activates an annotation tool (e.g., 'ink' , 'highlight' ). Pass null to deactivate. |
getActiveTool() | Returns the currently active AnnotationTool object, or null . |
addTool(tool) | Registers a new custom AnnotationTool . |
deleteAnnotation(..) | Deletes an annotation from a page. |
getSelectedAnnotation() | Returns the currently selected TrackedAnnotation object, or null . |
onStateChange(cb) | Subscribes to any change in the annotation state. Returns an unsubscribe function. |
onAnnotationEvent(cb) | Subscribes to events like annotation creation, updates, or deletion. Returns an unsubscribe function. |
Need Help?
Join our community for support, discussions, and to contribute to EmbedPDF's development.