Stamp Plugin
The Stamp Plugin extends the Annotation Plugin with reusable rubber-stamp libraries. Instead of treating every stamp as a one-off image, you can preload curated stamp sets, let users browse and place them, and even turn annotations they create in the viewer into reusable stamps at runtime.
Out of the box, the plugin is designed around two workflows:
- Using preloaded libraries for common review stamps like Approved, Draft, or Confidential.
- Creating custom libraries from annotations or imported PDFs, then exporting those libraries for later reuse.
Stamps render through the existing AnnotationLayer. In React, StampPluginPackage already registers the preview renderer used while the user is hovering a stamp over the page, so you do not need to add a separate layer component.
Installation
The Stamp Plugin builds on top of the Annotation Plugin and its interaction dependencies. The i18n plugin is optional, but recommended if you want the default manifest-backed stamp library to follow the active locale.
npm install @embedpdf/plugin-stamp @embedpdf/plugin-annotation @embedpdf/plugin-interaction-manager @embedpdf/plugin-selection @embedpdf/plugin-historyOptional localization support:
npm install @embedpdf/plugin-i18nRegistration
Import StampPluginPackage, the Annotation Plugin, and the Annotation Plugin dependencies. Register the dependencies first, then the annotation plugin, then the stamp plugin.
By default, the stamp plugin:
- Loads a localized standard stamp manifest from
@embedpdf/default-stamps. - Creates a writable
customlibrary the first time you save a user-generated stamp.
import { createPluginRegistration } from '@embedpdf/core'
import { EmbedPDF } from '@embedpdf/core/react'
// ... other imports
import { InteractionManagerPluginPackage } from '@embedpdf/plugin-interaction-manager/react'
import { SelectionPluginPackage } from '@embedpdf/plugin-selection/react'
import { HistoryPluginPackage } from '@embedpdf/plugin-history/react'
import { AnnotationPluginPackage } from '@embedpdf/plugin-annotation/react'
import { StampPluginPackage } from '@embedpdf/plugin-stamp/react'
const plugins = [
// ... essential viewer plugins like DocumentManager, Viewport, Scroll, Render
createPluginRegistration(DocumentManagerPluginPackage, { /* ... */ }),
createPluginRegistration(ViewportPluginPackage),
createPluginRegistration(ScrollPluginPackage),
createPluginRegistration(RenderPluginPackage),
// Annotation dependencies first
createPluginRegistration(InteractionManagerPluginPackage),
createPluginRegistration(SelectionPluginPackage),
createPluginRegistration(HistoryPluginPackage),
// Annotation must be registered before stamps
createPluginRegistration(AnnotationPluginPackage, {
annotationAuthor: 'Jane Doe',
}),
// StampPluginPackage registers the hover preview utility for React
createPluginRegistration(StampPluginPackage, {
defaultLibrary: {
id: 'custom',
name: 'Custom Stamps',
categories: ['custom', 'sidebar'],
},
}),
]Usage
1. Render Stamps Through <AnnotationLayer />
Stamp annotations are created, previewed, and selected through the Annotation Plugin. That means your page renderer should look just like a normal annotation-enabled viewer: wrap the page in PagePointerProvider, render the document, then render SelectionLayer and AnnotationLayer.
import { PagePointerProvider } from '@embedpdf/plugin-interaction-manager/react'
import { AnnotationLayer } from '@embedpdf/plugin-annotation/react'
<Scroller
documentId={activeDocumentId}
renderPage={({ pageIndex }) => (
<PagePointerProvider
documentId={activeDocumentId}
pageIndex={pageIndex}
>
<RenderLayer documentId={activeDocumentId} pageIndex={pageIndex} />
<SelectionLayer documentId={activeDocumentId} pageIndex={pageIndex} />
<AnnotationLayer
documentId={activeDocumentId}
pageIndex={pageIndex}
/>
</PagePointerProvider>
)}
/>2. Build a Stamp Sidebar
The React package includes hooks and components for building your own stamp browser:
useStampLibraries()gives you the loaded libraries.useStampsByLibrary(libraryId, category)returns the stamps you want to display.useActiveStamp(documentId)tells you which stamp is currently armed for placement.useStampCapability()gives you the plugin API.StampImgrenders a stamp thumbnail from a library page.
import {
StampImg,
useActiveStamp,
useStampCapability,
useStampLibraries,
useStampsByLibrary,
type StampDefinition,
} from '@embedpdf/plugin-stamp/react'
const StampSidebar = ({ documentId, selectedLibraryId }) => {
const { libraries } = useStampLibraries()
const { provides: stampCapability } = useStampCapability()
const stamps = useStampsByLibrary(selectedLibraryId, 'sidebar')
const activeStamp = useActiveStamp(documentId)
const handleStampClick = (libraryId: string, stamp: StampDefinition) => {
stampCapability
?.forDocument(documentId)
.activateStampPlacement(libraryId, stamp)
}
return (
<div>
{libraries.map((library) => (
<div key={library.id}>{library.name}</div>
))}
{stamps.map(({ library, stamp }) => {
const isActive =
activeStamp?.libraryId === library.id &&
activeStamp.stamp.id === stamp.id
return (
<button
key={`${library.id}-${stamp.id}`}
onClick={() => handleStampClick(library.id, stamp)}
>
<StampImg
libraryId={library.id}
pageIndex={stamp.pageIndex}
width={120}
/>
<span>{stamp.subject}</span>
{isActive && <span>placing</span>}
</button>
)
})}
</div>
)
}When a user clicks a stamp in your sidebar, the plugin switches the annotation tool to the rubber-stamp tool and shows a live preview as they move the pointer over the page.
3. Create a Custom Stamp From an Existing Annotation
If your users can draw annotations, you can turn those annotations into reusable stamps. This is a good fit for approval marks, signatures, custom seals, or reusable review graphics.
import { PdfAnnotationName } from '@embedpdf/models'
import { useAnnotation } from '@embedpdf/plugin-annotation/react'
import { useStampCapability } from '@embedpdf/plugin-stamp/react'
const CreateStampButton = ({ documentId }: { documentId: string }) => {
const { provides: annotation } = useAnnotation(documentId)
const { provides: stampCapability } = useStampCapability()
const handleCreateStamp = () => {
const selected = annotation?.getSelectedAnnotation()
if (!selected || !stampCapability) return
stampCapability
.forDocument(documentId)
.createStampFromAnnotation(
selected.object,
{
name: PdfAnnotationName.Custom,
subject: 'Reviewed by Legal',
categories: ['custom', 'sidebar'],
},
'custom',
)
}
return <button onClick={handleCreateStamp}>Create Stamp From Selection</button>
}The plugin exports the selected annotation’s appearance into a one-page PDF and stores that page in the target library. If the target library does not exist yet, the configured defaultLibrary is created automatically.
4. Export a Custom Library
Once users have built up a custom library, you can export it as a PDF and persist the accompanying metadata however you like.
import { useStampCapability } from '@embedpdf/plugin-stamp/react'
const ExportButton = () => {
const { provides: stampCapability } = useStampCapability()
const handleExport = () => {
stampCapability?.exportLibrary('custom').wait((exported) => {
console.log(exported.name) // "Custom Stamps"
console.log(exported.pdf) // ArrayBuffer with one page per stamp
console.log(exported.stamps) // Stamp metadata for each page
})
}
return <button onClick={handleExport}>Export Custom Library</button>
}exportLibrary() returns both the rendered PDF and the stamp metadata. That makes it easy to save runtime-created libraries to your backend and later reload them with loadLibrary() or by publishing a manifest.
Live Example
The example below demonstrates both main workflows on one screen:
- Browse the built-in stamp libraries and place a stamp.
- Draw a square annotation, select it, save it into the custom library, and export that library as a PDF.
Bring Your Own Stamp Library
Stamp libraries are intentionally simple:
- Each stamp is one page in a PDF.
- Each entry in
stamps[]points at apageIndexin that PDF. - Library-level
categoriesapply to all stamps in the library. - Stamp-level
categorieslet you filter or organize specific stamps differently.
Manifest Format
The manifest format is designed for publishing a library alongside a PDF file. Relative pdf paths are resolved relative to the manifest URL.
{
"id": "standard",
"name": "Standard Stamps",
"categories": ["sidebar"],
"pdf": "stamps.pdf",
"stamps": [
{ "id": "approved", "pageIndex": 0, "name": "Approved", "subject": "Approved" },
{ "id": "draft", "pageIndex": 1, "name": "Draft", "subject": "Draft" },
{ "id": "confidential", "pageIndex": 2, "name": "Confidential", "subject": "Confidential" }
]
}Option A: Load Libraries From Manifests
Use manifests when you want to host a reusable library as static files:
createPluginRegistration(StampPluginPackage, {
manifests: [
{
url: '/stamps/en/manifest.json',
fallbackLocale: 'en',
},
]
})You can also load the same thing later at runtime with stampCapability.loadLibraryFromManifest(url).
Option B: Preload Libraries Inline
Use libraries when you already have the PDF URL or ArrayBuffer and the metadata available in your app:
createPluginRegistration(StampPluginPackage, {
libraries: [
{
id: 'review',
name: 'Review Stamps',
pdf: '/stamps/review-stamps.pdf',
readonly: true,
categories: ['sidebar'],
stamps: [
{
id: 'approved',
pageIndex: 0,
name: PdfAnnotationName.Approved,
subject: 'Approved',
},
{
id: 'rejected',
pageIndex: 1,
name: PdfAnnotationName.Rejected,
subject: 'Rejected',
},
],
},
],
})You can load the same shape dynamically through the capability API:
stampCapability?.loadLibrary({
name: 'Uploaded Stamps',
pdf: uploadedPdfBytes,
stamps: uploadedStampDefinitions,
})Persist Runtime-Created Libraries
If users create their own libraries in the browser, a common pattern is:
- Let them build or edit stamps at runtime.
- Call
exportLibrary()to get the PDF andstamps[]metadata. - Save both to your backend.
- Reload the same library later with
loadLibrary()or publish it as a manifest-backed library.
If you want to create an empty library first, use createNewLibrary(name, options) and then add stamp pages later with addStampToLibrary(libraryId, stamp, pdf).
API Reference
Configuration (StampPluginConfig)
| Option | Type | Description |
|---|---|---|
libraries | StampLibraryConfig[] | Preloads one or more libraries from a PDF URL or ArrayBuffer plus stamp metadata. |
manifests | StampManifestSource[] | Loads one or more manifest-backed libraries. If the URL contains {locale}, the plugin replaces it with the current locale when the i18n plugin is available. |
defaultLibrary | DefaultLibraryConfig | false | Configures the writable library used for runtime-created stamps. Set it to false to disable automatic default-library creation. |
Hook: useStampCapability()
Connects your component to the global Stamp Plugin capability.
Returns
| Property | Type | Description |
|---|---|---|
provides | StampCapability | null | The stamp API object, or null until the plugin is ready. |
Hook: useStampLibraries()
Keeps your component in sync with the currently loaded stamp libraries.
Returns
| Property | Type | Description |
|---|---|---|
libraries | StampLibrary[] | The loaded libraries, including manifest-backed and runtime-created libraries. |
provides | StampCapability | null | The same capability returned by useStampCapability(). |
Hook: useStampsByLibrary(libraryId?, category?)
Returns a flattened array of stamps filtered by library and optional category.
| Argument | Type | Description |
|---|---|---|
libraryId | string | undefined | The library ID to filter by. Use 'all' or undefined to include every library. |
category | string | undefined | Optional category filter applied to both library-level and stamp-level categories. |
Hook: useActiveStamp(documentId)
Returns the stamp currently armed for placement in the specified document.
| Return Type | Description |
|---|---|
ActiveStampInfo | null | Includes the libraryId and stamp being placed, or null if no stamp is active. |
Component: <StampImg />
Renders a thumbnail of a stamp by rasterizing the matching page from its library.
| Prop | Type | Description |
|---|---|---|
libraryId | string | Required. The library that owns the stamp page. |
pageIndex | number | Required. The page index within the library PDF. |
width | number | Required. The target thumbnail width in CSS pixels. |
dpr | number | Optional device pixel ratio override for sharper previews. |
StampCapability Methods
| Method | Description |
|---|---|
getLibraries() | Returns every currently loaded library. |
getStampsByCategory(category) | Returns a flattened list of stamps whose library or individual stamp matches the category. |
loadLibrary(config) | Loads a library from a StampLibraryConfig. |
loadLibraryFromManifest(url) | Loads a library from a manifest URL at runtime. |
createNewLibrary(name, options) | Creates an empty library that can be populated later. |
addStampToLibrary(libraryId, stamp, pdf) | Adds a new one-page stamp PDF to an editable library. |
exportLibrary(id) | Exports a library as { name, pdf, stamps, categories }. |
forDocument(documentId) | Returns a document-scoped StampScope for placement and creation actions. |
StampScope Methods
| Method | Description |
|---|---|
activateStampPlacement(libraryId, stamp) | Arms a specific stamp for placement in the current document. |
activateStampPlacementById(libraryId, stampId) | Looks up a stamp by ID, then arms it for placement. |
createStampFromAnnotation(annotation, stamp, libraryId?) | Turns one annotation into a reusable stamp in the target library. |
createStampFromAnnotations(annotations, stamp, libraryId?) | Creates one stamp from a group of annotations. |
getActiveStamp() | Returns the currently active stamp for this document, or null. |
onActiveStampChange | Event hook that fires when the active stamp changes for the document. |
Need Help?
Join our community for support, discussions, and to contribute to EmbedPDF's development.