EmbedPDF

Signature Plugin

The Signature Plugin extends the Annotation Plugin to provide a dedicated workflow for electronic signatures. It includes ready-to-use UI components for drawing and typing signatures, helper composables for image uploads, and an API for saving them as reusable entries.

Once a signature is saved as an entry, users can easily click to arm the tool and stamp their signature anywhere on the PDF document.

ℹ️

Signatures are placed as standard PDF annotations (Ink for drawn signatures, Stamps for typed/uploaded signatures). They render automatically through your existing <AnnotationLayer />.

Installation

This plugin depends on the Annotation Plugin and its interaction dependencies.

npm install @embedpdf/plugin-signature @embedpdf/plugin-annotation @embedpdf/plugin-interaction-manager @embedpdf/plugin-selection @embedpdf/plugin-history

Registration

Import SignaturePluginPackage and add it to your plugins array after the Annotation Plugin dependencies and 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' import { SignaturePluginPackage, SignatureMode } from '@embedpdf/plugin-signature/vue' const plugins = [ // ... essential viewer plugins (DocumentManager, Viewport, Render, Scroll) createPluginRegistration(DocumentManagerPluginPackage, { /* ... */ }), // Annotation dependencies createPluginRegistration(InteractionManagerPluginPackage), createPluginRegistration(SelectionPluginPackage), createPluginRegistration(HistoryPluginPackage), // Annotation plugin createPluginRegistration(AnnotationPluginPackage), // Signature plugin createPluginRegistration(SignaturePluginPackage, { mode: SignatureMode.SignatureOnly, // or SignatureAndInitials defaultSize: { width: 150, height: 50 }, // Default placement size }), ]

Usage

1. Rendering Signatures

Because signatures are specialized annotations, you do not need a special layer. Simply render the <AnnotationLayer /> inside your page scroller.

<script setup> import { PagePointerProvider } from '@embedpdf/plugin-interaction-manager/vue' import { AnnotationLayer } from '@embedpdf/plugin-annotation/vue' </script> <template> <Scroller :document-id="documentId"> <template #default="{ page }"> <PagePointerProvider :document-id="documentId" :page-index="page.pageIndex"> <RenderLayer :document-id="documentId" :page-index="page.pageIndex" /> <SelectionLayer :document-id="documentId" :page-index="page.pageIndex" /> <AnnotationLayer :document-id="documentId" :page-index="page.pageIndex" /> </PagePointerProvider> </template> </Scroller> </template>

2. Creating Signatures (The UI Pads)

The plugin exports <SignatureDrawPad /> and <SignatureTypePad /> components. These handle the complexities of tracking pointer events, rendering canvas strokes, applying fonts, and auto-cropping the results to remove transparent whitespace.

You can place these inside modals or sidebars.

<script setup> import { SignatureDrawPad, SignatureTypePad } from '@embedpdf/plugin-signature/vue' function handleResult(result) { // result is either SignatureInkFieldDefinition or SignatureStampFieldDefinition } </script> <template> <SignatureDrawPad strokeColor="#0000FF" :strokeWidth="3" @result="handleResult" /> <SignatureTypePad color="#0000FF" fontFamily="'Dancing Script', cursive" @result="handleResult" /> </template>

3. Uploading Signatures

For image uploads, use the useSignatureUpload composable to handle the file picker, drag-and-drop, and automatic image-to-canvas extraction.

<script setup> import { useSignatureUpload } from '@embedpdf/plugin-signature/vue' const { openFilePicker, inputRef, handleFileInputChange } = useSignatureUpload({ onResult: (result) => { // Save to the capability (see step 4) }, }) </script> <template> <button type="button" @click="openFilePicker"> Upload Image </button> <input type="file" ref="inputRef" accept="image/png,image/jpeg,image/svg+xml" class="hidden" @change="handleFileInputChange" /> </template>

4. Saving and Placing Signatures

Once you have a result from one of the pads or the upload hook, save it to the plugin’s state using useSignatureCapability.

<script setup> import { useSignatureCapability, useSignatureEntries, useActivePlacement } from '@embedpdf/plugin-signature/vue' const props = defineProps<{ documentId: string }>() const { entries } = useSignatureEntries(); const { provides: signatureCapability } = useSignatureCapability(); const activePlacement = useActivePlacement(() => props.documentId); const handleSaveNew = (result) => { signatureCapability.value?.addEntry({ signature: result }); } </script> <template> <div> <div v-for="entry in entries" :key="entry.id" :class="{ 'ring-2 ring-blue-500': activePlacement?.entryId === entry.id }"> <img :src="entry.signature.previewDataUrl" alt="Signature" /> <button @click="signatureCapability?.forDocument(documentId).activateSignaturePlacement(entry.id)"> Use </button> <button @click="signatureCapability?.removeEntry(entry.id)"> Delete </button> </div> </div> </template>

5. Persisting Signatures (localStorage / Backend)

The plugin ships with serializeEntries and deserializeEntries utilities that convert entries to and from a JSON-safe format, and an onEntriesChange event hook that fires whenever entries are added, removed, or loaded. Together they make auto-persisting signatures trivial.

<script setup> import { watchEffect, onUnmounted } from 'vue' import { useSignatureCapability, serializeEntries, deserializeEntries, } from '@embedpdf/plugin-signature/vue' const STORAGE_KEY = 'my-signatures' const { provides: signatureCapability } = useSignatureCapability() let unsubscribe watchEffect(() => { if (!signatureCapability.value) return // Load previously saved entries on mount const raw = localStorage.getItem(STORAGE_KEY) if (raw) { signatureCapability.value.loadEntries(deserializeEntries(JSON.parse(raw))) } // Auto-save whenever entries change unsubscribe = signatureCapability.value.onEntriesChange((entries) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(serializeEntries(entries))) }) }) onUnmounted(() => unsubscribe?.()) </script>

Live Example

This example demonstrates the full signature workflow: drawing, typing, and uploading signatures, saving them to your collection, and placing them on the document.

API Reference

Configuration (SignaturePluginConfig)

OptionTypeDescription
modeSignatureModeDetermines if the plugin tracks only signatures (SignatureMode.SignatureOnly) or both signatures and initials (SignatureMode.SignatureAndInitials).
defaultSize{ width: number, height: number }The default bounding box size applied when placing a signature. Default: { width: 150, height: 50 }

Hook: useSignatureCapability()

Returns the global plugin API.

SignatureCapability Methods

MethodDescription
getEntries()Returns all saved SignatureEntry objects.
addEntry(entry)Saves a new signature entry. Returns the generated UUID.
removeEntry(id)Deletes a signature entry.
exportEntries()Returns all SignatureEntry objects including their binary data. Use with serializeEntries() for persistence.
loadEntries(entries)Hydrates the plugin with previously exported entries. Use with deserializeEntries() when loading from JSON.
onEntriesChangeEvent hook that fires whenever entries are added, removed, or loaded. Subscribe with onEntriesChange((entries) => { ... }) — returns an unsubscribe function.
forDocument(documentId)Returns a SignatureScope scoped to the current document for placement actions.

Hook: useSignatureEntries()

Reactive hook that returns { entries }. The entries array automatically updates when signatures are added or removed.

Hook: useActivePlacement(documentId)

Reactive hook that returns an ActivePlacementInfo object if a signature is currently armed for placement, or null.

interface ActivePlacementInfo { entryId: string; kind: SignatureFieldKind; // 'signature' | 'initials' }

SignatureScope Methods (Returned by forDocument)

MethodDescription
activateSignaturePlacement(entryId)Arms a specific signature entry for placement on the PDF.
activateInitialsPlacement(entryId)Arms a specific initials entry for placement on the PDF.
deactivatePlacement()Cancels placement mode.

Component: <SignatureDrawPad />

An auto-cropping canvas component that tracks pointer events to capture hand-drawn signatures.

Prop/EventTypeDescription
@result(result) => voidFires whenever the user draws on the canvas. Provides the SignatureInkFieldDefinition.
strokeColorstringThe color of the ink line.
strokeWidthnumberThe thickness of the ink line.

You can call .clear() on the component template ref to reset it.

Component: <SignatureTypePad />

An auto-cropping text input component that converts typed text into a high-resolution stamp image.

Prop/EventTypeDescription
@result(result) => voidFires when text changes. Provides a SignatureStampFieldDefinition including imageData.
fontFamilystringThe CSS font-family to use (e.g. 'Dancing Script', cursive).
colorstringThe text color.
fontSizenumberThe base font size used for the canvas generation.
placeholderstringThe placeholder text.

You can call .clear() on the component template ref to reset it.

Last updated on April 3, 2026

Need Help?

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