React API Reference
@trexolab/verifykit-react
React PDF viewer with signature verification, plugin architecture, and theme support. Render PDFs, verify digital signatures, and compose viewer features using 24 independent plugins.
Components
<VerifyKitProvider>
Context provider that initializes the WASM engine, configures the verifier, sets the theme, and provides i18n. Must wrap all VerifyKit components.
<VerifyKitProvider config={config}>
<App />
</VerifyKitProvider>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
config | VerifyKitConfig | No | Provider configuration (see VerifyKitConfig type below) |
children | ReactNode | Yes | Child components |
<Viewer>
The recommended plugin-based PDF viewer component. Accepts plugins for composable features.
<Viewer
ref={viewerRef}
fileBuffer={arrayBuffer}
fileName="report.pdf"
plugins={[layout.plugin]}
onDocumentLoaded={(doc) => console.log('Pages:', doc.numPages)}
onOpenFile={(file) => verification.load(file)}
signatures={verification.signatures}
unsignedFields={verification.unsignedFields}
verificationStatus={verification.status}
/>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
fileBuffer | ArrayBuffer | null | No | PDF file bytes |
fileName | string | No | Display file name |
plugins | ViewerPlugin[] | No | Array of viewer plugins to install |
initialState | Partial<ViewerStoreState> | No | Initial store state overrides |
signatures | PdfSignature[] | No | Reactive signature data (synced to store) |
unsignedFields | UnsignedSigField[] | No | Reactive unsigned field data |
verificationStatus | VerificationStatus | No | Reactive overall verification status |
onDocumentLoaded | (doc: PDFDocumentProxy) => void | No | Called when the PDF document loads |
onPageCountChange | (n: number) => void | No | Called when page count is known |
onReady | () => void | No | Called when the viewer is ready |
onOpenFile | (file: File) => void | No | File open handler (enables drag-drop) |
onContextMenu | (e: React.MouseEvent) => void | No | Context menu handler |
onLoadError | (error: LoadError) => void | No | Called when the PDF fails to load |
onRevalidate | () => void | No | Called when user requests re-verification |
signaturePanelOpen | boolean | No | Auto-open the signature panel |
isActive | boolean | No | Tab isolation — disable global listeners when hidden (default: true) |
verifying | boolean | No | Show loading indicator while verification is in progress |
renderError | (error: LoadError) => ReactNode | No | Custom error UI renderer |
renderLayout | (slots) => ReactNode | No | Custom layout render function |
Ref handle (ViewerHandle):
interface ViewerHandle {
scrollToPage(n: number): void
getStore(): ViewerStore
}const viewerRef = useRef<ViewerHandle>(null)
viewerRef.current.scrollToPage(5)<WelcomeScreen>
A drop-target landing screen for when no file is loaded.
<WelcomeScreen
onOpenFile={(file: File) => verification.load(file)}
title="My PDF Viewer"
subtitle="Drag and drop a PDF here"
/>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
onOpenFile | (file: File) => void | Yes | Called when a file is dropped or selected |
title | string | No | Heading text |
subtitle | string | No | Subheading text |
accept | string | No | File type filter for file picker (default: '.pdf,application/pdf') |
<PdfViewer> (Legacy)
The original monolithic viewer component. Still fully supported for backward compatibility but not extensible via plugins. Use <Viewer> with the plugin system for new projects.
<PdfViewer
ref={viewerRef}
fileBuffer={arrayBuffer}
signatures={signatures}
onWidgetClick={(sig, fieldName) => {}}
/><DocumentMessageBar>
Colored status bar displayed above the viewer showing the overall verification result.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
status | VerificationStatus | Yes | Overall document verification status |
signatures | PdfSignature[] | Yes | All document signatures |
onShowPanel | () => void | No | Called when user clicks to show signature panel |
panelVisible | boolean | No | Whether the signature panel is currently visible |
<SignatureListPanel>
Side panel listing all signatures with status icons. Click a signature to view its details.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
signatures | PdfSignature[] | Yes | All document signatures |
unsignedFields | UnsignedSigField[] | No | Unsigned signature fields |
selectedIdx | number | Yes | Currently selected signature index |
onSelect | (i: number, tab?: string) => void | Yes | Selection handler |
onNavigate | (i: number) => void | No | Navigate to signature in PDF |
onClose | () => void | No | Close panel handler |
onRevalidate | () => void | No | Re-verify signatures |
isRevalidating | boolean | No | Show revalidation spinner |
<SignaturePropertiesModal>
Tabbed modal dialog showing detailed signature information, validity checks, certificate chain, and timestamp data.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
sig | PdfSignature | null | Yes | The signature to display |
fieldName | string | Yes | Form field name |
open | boolean | Yes | Whether the modal is open |
onClose | () => void | Yes | Close handler |
initialTab | 'details' | 'certificates' | 'tsa' | 'pades' | No | Initially active tab |
<CertificateViewer>
Interactive certificate chain tree viewer. Displays the full certificate chain from signer to root CA with expandable details.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
cert | CertificateInfo | Yes | Certificate to display |
isTsa | boolean | No | Whether this is a TSA certificate |
<PasswordDialog>
Password prompt dialog for encrypted/password-protected PDFs.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
error | boolean | Yes | Whether a previous password attempt failed |
onSubmit | (pwd: string) => void | Yes | Submit handler with entered password |
onCancel | () => void | Yes | Cancel handler |
<SignatureStatusIcon>
Status icon component showing valid/invalid/warning/unknown state.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
status | VerificationStatus | Yes | Verification status to display |
size | number | No | Icon size in pixels |
<ValidityChecklist>
Expandable list of all verification checks for a signature.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
sig | PdfSignature | Yes | Signature to show checks for |
<PdfViewerErrorBoundary>
Error boundary wrapper for the PDF viewer. Catches render errors and shows a fallback UI.
Props:
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Yes | Child components |
fallback | ReactNode | No | Custom fallback UI |
onReset | () => void | No | Called when the user resets the error boundary |
Hooks
useVerification()
Manages PDF loading, verification, and result state. Must be used inside a <VerifyKitProvider>.
function useVerification(): VerificationStateReturns:
interface VerificationState {
load(input: PdfInput, fileName?: string): Promise<VerificationResult>
revalidate(): Promise<VerificationResult | null>
reset(): void
fileBuffer: ArrayBuffer | null
originalFileBuffer: ArrayBuffer | null
fileName: string
result: VerificationResult | null
metadata: DocumentMetadata | null
permissions: DocumentPermissions | null
signatures: PdfSignature[]
unsignedFields: UnsignedSigField[]
status: VerificationStatus | null
isLoading: boolean
error: LoadError | null
}Example:
const verification = useVerification()
await verification.load(file) // File, ArrayBuffer, Uint8Array, or URL
verification.signatures // PdfSignature[]
verification.status // 'valid' | 'invalid' | 'warning' | ...
verification.isLoading // boolean
verification.error // LoadError | null (object with name and message)
await verification.revalidate() // Re-verify signatures on current buffer
verification.reset() // Clear stateuseViewerStore(selector)
Subscribe to a slice of the viewer store. Re-renders only when the selected value changes. Must be used inside <Viewer>.
function useViewerStore<T>(selector: (state: ViewerStoreState) => T): TExample:
const scale = useViewerStore(s => s.scale)
const [page, total] = useViewerStore(s => [s.currentPage, s.totalPages])useViewerStoreKey(key)
Subscribe to a single key in the viewer store.
function useViewerStoreKey<K extends keyof ViewerStoreState>(key: K): ViewerStoreState[K]Example:
const currentPage = useViewerStoreKey('currentPage')useViewerStoreUpdate()
Get the store's update function for dispatching partial state updates.
function useViewerStoreUpdate(): (partial: Partial<ViewerStoreState>) => voidExample:
const update = useViewerStoreUpdate()
update({ scale: 1.5, fitMode: 'none' })useStore()
Returns the raw ViewerStore instance for advanced use (batch updates, direct subscriptions).
function useStore(): ViewerStoreuseContainerSize(ref)
Responsive breakpoint hook that reports the container dimensions.
function useContainerSize(ref: React.RefObject<HTMLElement>): { width: number; height: number }usePinchZoom(ref, onZoom)
Touch pinch-zoom gesture handler for mobile support.
function usePinchZoom(
ref: React.RefObject<HTMLElement>,
onZoom: (scaleDelta: number) => void,
): voidPlugin Functions
All plugins are factory functions that return a ViewerPlugin. Always wrap plugin creation in useState to ensure a stable instance across renders:
const [layout] = useState(() => defaultLayoutPlugin())Meta Plugin
defaultLayoutPlugin(options?)
Composes all 24 plugins into a batteries-included experience. The recommended starting point for most applications.
function defaultLayoutPlugin(options?: DefaultLayoutPluginOptions): DefaultLayoutPluginResultOptions:
interface DefaultLayoutPluginOptions {
accessibility?: AccessibilityPluginOptions
disable?: {
search?: boolean
print?: boolean
download?: boolean
fullscreen?: boolean
theme?: boolean
rotation?: boolean
selection?: boolean
sidebar?: boolean
signatures?: boolean
highlights?: boolean
openFile?: boolean
properties?: boolean
shortcuts?: boolean
contextMenu?: boolean
accessibility?: boolean
}
toolbar?: ToolbarPluginOptions
}
interface AccessibilityPluginOptions {
initialScale?: 'compact' | 'default' | 'large' | 'extra-large'
persist?: boolean // default: true — save preference to localStorage
}Result:
interface DefaultLayoutPluginResult {
plugin: ViewerPlugin
zoom: ZoomPluginApi
navigation: PageNavigationPluginApi
rotation: RotationPluginApi
search: SearchPluginApi
print: PrintPluginApi
download: DownloadPluginApi
theme: ThemePluginApi
fullscreen: FullscreenPluginApi
selection: SelectionPluginApi
scrollMode: ScrollModePluginApi
spreadMode: SpreadModePluginApi
signature: SignaturePluginApi
sidebar: SidebarPluginApi
accessibility: AccessibilityPluginApi
}Example:
// All features
const [layout] = useState(() => defaultLayoutPlugin())
// Selective features
const [layout] = useState(() =>
defaultLayoutPlugin({
disable: { print: true, download: true, contextMenu: true },
})
)
<Viewer fileBuffer={buffer} plugins={[layout.plugin]} />Navigation Plugins
| Plugin | API Type | Description |
|---|---|---|
zoomPlugin() | ZoomPluginApi | Zoom controls: zoomIn(), zoomOut(), zoomTo(scale), setFitMode(mode) |
pageNavigationPlugin() | PageNavigationPluginApi | Page navigation: goToPage(n), goToNextPage(), goToPreviousPage(), goToFirstPage(), goToLastPage() |
rotationPlugin() | RotationPluginApi | Document rotation: rotateCW(), rotateCCW() |
scrollModePlugin() | ScrollModePluginApi | Scroll mode: setScrollMode(mode) |
spreadModePlugin() | SpreadModePluginApi | Spread/facing mode: setSpreadMode(mode) |
Content Plugins
| Plugin | API Type | Description |
|---|---|---|
searchPlugin() | SearchPluginApi | Text search: open(), close() |
highlightPlugin() | -- | Text highlighting and selection display |
selectionPlugin() | SelectionPluginApi | Cursor tool selection: setCursorTool(tool) |
Action Plugins
| Plugin | API Type | Description |
|---|---|---|
printPlugin() | PrintPluginApi | Print the document: print() |
downloadPlugin() | DownloadPluginApi | Download the document: download() |
openFilePlugin() | -- | File open and drag-drop handling |
UI Plugins
| Plugin | API Type | Description |
|---|---|---|
toolbarPlugin() | -- | Toolbar with slot system for positioning controls |
sidebarPlugin() | SidebarPluginApi | Sidebar panel: toggle(tab?), open(tab), close() |
themePlugin() | ThemePluginApi | Theme control: toggleTheme(), setTheme(mode), getTheme() |
fullscreenPlugin() | FullscreenPluginApi | Fullscreen: enterFullscreen(), exitFullscreen(), toggleFullscreen() |
accessibilityPlugin() | AccessibilityPluginApi | UI font scale: setFontScale(scale), getFontScale() |
Panel Plugins
| Plugin | API Type | Description |
|---|---|---|
signaturePlugin() | SignaturePluginApi | Signature panel: openPanel(), closePanel(), togglePanel() |
thumbnailPlugin() | -- | Thumbnail sidebar tab |
bookmarkPlugin() | -- | Bookmark/outline sidebar tab |
attachmentPlugin() | -- | Attachment sidebar tab |
propertiesPlugin() | -- | Document properties modal |
Help Plugins
| Plugin | API Type | Description |
|---|---|---|
shortcutHelpPlugin() | -- | Keyboard shortcuts help panel |
contextMenuPlugin() | -- | Right-click context menu |
moreMenuPlugin() | -- | Overflow menu for toolbar items |
Types
VerifyKitConfig
Provider configuration, extending VerifyKitCoreConfig with viewer-specific options.
interface VerifyKitConfig extends VerifyKitCoreConfig {
workerUrl: string // REQUIRED. URL to the PDF.js worker script.
cMapUrl?: string // Default: '/cmaps/'
standardFontDataUrl?: string // Default: '/standard_fonts/'
theme?: ThemeConfig
embeddedFont?: boolean | string
toolbar?: ToolbarConfig
locale?: string // Default: 'en'
translations?: Partial<TranslationStrings>
}
interface ThemeConfig {
mode?: 'light' | 'dark' | 'system'
overrides?: Record<string, string> // CSS variable overrides
}ToolbarConfig
Controls which toolbar features are visible in the viewer. All fields default to true unless noted.
interface ToolbarConfig {
openFile?: boolean // default: false
pageNavigation?: boolean // default: true
zoom?: boolean // default: true
fitMode?: boolean // default: true
rotation?: boolean // default: true
scrollMode?: boolean // default: true
search?: boolean // default: true
print?: boolean // default: true
download?: boolean // default: false
themeToggle?: boolean // default: true
fullscreen?: boolean // default: true
signaturePanel?: boolean // default: true
cursorTool?: boolean // default: true
moreMenu?: boolean // default: true
documentProperties?: boolean // default: true
}Recommended CDN URL:
https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs
Self-hosted: Copy node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs to your public directory and pass the local path.
ViewerPlugin
Plugin interface for extending the viewer with features.
interface ViewerPlugin {
name: string
dependencies?: string[]
composedPlugins?: ViewerPlugin[]
// Lifecycle hooks
install?(ctx: PluginContext): void
onDocumentLoad?(e: DocumentLoadEvent): void
onDocumentUnload?(): void
onPageChange?(e: PageChangeEvent): void
onZoomChange?(e: ZoomChangeEvent): void
onRotationChange?(e: RotationChangeEvent): void
destroy?(): void
// UI contributions
renderToolbarSlot?: Partial<ToolbarSlots>
sidebarTabs?: SidebarTabDefinition[]
renderOverlay?: (props: OverlayRenderProps) => React.ReactNode
renderRightPanel?: (props: OverlayRenderProps) => React.ReactNode
renderPageOverlay?: (props: PageOverlayRenderProps) => React.ReactNode
transformToolbarSlots?: (slots: ToolbarSlots) => ToolbarSlots
}PluginContext (Viewer)
Context passed to a plugin's install() method.
interface PluginContext {
store: ViewerStore
getDocument(): PDFDocumentProxy | null
scrollToPage(pageNum: number): void
getScrollContainer(): HTMLElement | null
getViewerContainer(): HTMLElement | null
registerShortcut(shortcut: KeyboardShortcut): () => void
onOpenFile?: (file: File) => void
onRevalidate?: () => void
t(key: string): string
}ViewerHandle
Ref handle exposed by the <Viewer> component.
interface ViewerHandle {
scrollToPage(n: number): void
getStore(): ViewerStore
}ViewerStore
Lightweight pub-sub reactive store that drives the viewer state.
interface ViewerStore {
get<K extends keyof ViewerStoreState>(key: K): ViewerStoreState[K]
getState(): ViewerStoreState
update(partial: Partial<ViewerStoreState>): void
subscribe<K extends keyof ViewerStoreState>(
key: K,
listener: (newVal: ViewerStoreState[K], oldVal: ViewerStoreState[K]) => void,
): () => void
subscribeAll(listener: (key: string, newVal: unknown, oldVal: unknown) => void): () => void
batch(fn: () => void): void
reset(): void
destroy(): void
}State shape:
| Category | Keys |
|---|---|
| Document | document, fileBuffer, originalFileBuffer, fileName, loadState, loadError |
| Navigation | currentPage, totalPages |
| Zoom | scale, fitMode |
| Rotation | rotation |
| Layout | scrollMode, spreadMode, cursorTool |
| Theme | themeMode |
| Fullscreen | isFullscreen |
| Verification | signatures, unsignedFields, verificationStatus, isRevalidating |
| UI panels | sidebarOpen, sidebarTab, sigPanelOpen, findOpen, propertiesModalOpen, shortcutHelpOpen, aboutModalOpen, contextMenuPos, sigModalIndex, sigModalFieldName, sigModalTab, highlightedSigIndex |
| Password | passwordNeeded, passwordError |
Event Types
interface DocumentLoadEvent {
document: PDFDocumentProxy
numPages: number
}
interface PageChangeEvent {
currentPage: number
previousPage: number
}
interface ZoomChangeEvent {
scale: number
previousScale: number
fitMode: ViewerStoreState['fitMode']
}
interface RotationChangeEvent {
rotation: ViewerStoreState['rotation']
previousRotation: ViewerStoreState['rotation']
}KeyboardShortcut
interface KeyboardShortcut {
id: string
key: string
ctrl?: boolean
shift?: boolean
alt?: boolean
handler: (e: KeyboardEvent) => void
allowInInput?: boolean
description?: string
}SidebarTabDefinition
interface SidebarTabDefinition {
id: string
label: string
icon: React.ReactNode
component: React.ComponentType<{ store: ViewerStore }>
canRender?: (state: ViewerStoreState) => boolean
order: number
}Toolbar Slots
interface ToolbarSlots {
SearchPopover?: ToolbarSlotRender
GoToPreviousPage?: ToolbarSlotRender
CurrentPageInput?: ToolbarSlotRender
NumberOfPages?: ToolbarSlotRender
GoToNextPage?: ToolbarSlotRender
ZoomOut?: ToolbarSlotRender
Zoom?: ToolbarSlotRender
ZoomIn?: ToolbarSlotRender
Rotate?: ToolbarSlotRender
CursorTool?: ToolbarSlotRender
OpenFile?: ToolbarSlotRender
Download?: ToolbarSlotRender
Print?: ToolbarSlotRender
ThemeToggle?: ToolbarSlotRender
Fullscreen?: ToolbarSlotRender
MoreMenu?: ToolbarSlotRender
[custom: string]: ToolbarSlotRender | undefined
}
type ToolbarSlotRender = (props: { store: ViewerStore }) => React.ReactNodeRe-exported from Core
The React package re-exports all core types and functions for convenience:
Functions: createVerifier, verifyPdf, extractPdfMetadata, extractSignaturesFromPdf, getTrustStore, setTrustStoreConfig, resetTrustStore, ensureCryptoEngine, buf2hex, sha256hex, decompressFlate, computeUnsignedFields, oidToName, parseDn, isNode
Types: VerificationStatus, PdfSignature, VerificationResult, CertificateInfo, TimestampInfo, SignatureCheckResult, DocumentMetadata, DocumentPermissions, UnsignedSigField, VerifyKitCoreConfig, VerifyKitVerifier, VerifyKitPlugin, PluginContext (core), PdfInput, TrustStoreConfig, RevocationCheckResult, TrustStore
See the Core API Reference for documentation on these.
Error Handling
LoadError
Typed PDF loading/verification error. The name property classifies the error for programmatic handling and matches pdf.js exception names where applicable.
interface LoadError {
/** Semantic error type for programmatic handling */
name: LoadErrorName
/** Human-readable error message */
message: string
}LoadErrorName
Union of all recognized error classification names.
type LoadErrorName =
| 'InvalidPDFException'
| 'MissingPDFException'
| 'UnexpectedResponseException'
| 'PasswordException'
| 'AbortException'
| 'FormatError'
| 'NetworkError'
| 'UnsupportedInputError'
| 'VerificationError'
| 'UnknownErrorException'classifyPdfError(error)
Classify an unknown error into a typed LoadError. Preserves pdf.js exception names; everything else becomes UnknownErrorException.
function classifyPdfError(error: unknown): LoadErrorcreateLoadError(name, message)
Create a LoadError with a specific name and message.
function createLoadError(name: LoadErrorName, message: string): LoadErrorStatus & Styling Helpers
Status configuration constants and helper functions for mapping VerificationStatus to labels, colors, and display text. All color values reference CSS custom properties from the VerifyKit theme.
Constants
| Constant | Type | Description |
|---|---|---|
STATUS_LABEL | Record<VerificationStatus, string> | Human-readable label per status ('Valid', 'Invalid', etc.) |
STATUS_COLOR | Record<VerificationStatus, string> | Foreground text color CSS variable per status |
STATUS_BG | Record<VerificationStatus, string> | Background surface color CSS variable per status |
STATUS_STRIPE | Record<VerificationStatus, string> | Border/stripe color CSS variable per status |
STATUS_CFG | Record<VerificationStatus, StatusCfg> | Combined status banner config (color, bg, stripe, title) |
AVATAR_RING | Record<VerificationStatus, string> | Avatar ring color per status (signature modal header) |
PANEL_STRIPE | Record<VerificationStatus, string> | Left stripe color per status (signature list panel) |
StatusCfg
interface StatusCfg {
color: string
bg: string
stripe: string
title: string
}Functions
statusTextColor(status)
Returns the CSS color variable for status check rows and bullets.
function statusTextColor(status: VerificationStatus): stringgetStatusSentence(sig)
Returns an Adobe Reader DC-style status sentence for a signature. Handles deleted and not-yet-verified signatures.
function getStatusSentence(sig: PdfSignature): stringgetInvalidSub(sig)
Returns a detailed sub-message explaining why a signature is invalid (revoked, modified, expired, etc.).
function getInvalidSub(sig: PdfSignature): stringgetPillLabel(sig)
Returns the uppercase status label for the modal header badge (e.g. 'VALID', 'INVALID').
function getPillLabel(sig: PdfSignature): stringgetInitials(name)
Extracts initials from a signer name for avatar display. Returns first and last initials for multi-word names, or a single initial.
function getInitials(name: string): stringgetDisplayStatus(sig)
Returns the Adobe Reader DC-aligned display status for a signature. Accounts for the attempted field on revocation checks to differentiate "not checked" from "checked but unknown."
function getDisplayStatus(sig: PdfSignature): VerificationStatusoverallStatus(result)
Derives the document-level overall verification status from a VerificationResult. Returns 'invalid' if any active signature is invalid, 'valid' if all are valid, 'warning' otherwise.
function overallStatus(result: VerificationResult): VerificationStatusCheck Builders
Functions that construct validation check items from PdfSignature data. Shared between the full validity checklist and the compact signature list panel.
CheckItem
interface CheckItem {
status: VerificationStatus
label: string
text: string
detail?: string
}MiniCheckItem
interface MiniCheckItem {
status: VerificationStatus
label: string
}SummaryLine
interface SummaryLine {
status: VerificationStatus
text: string
}buildChecks(sig)
Builds the full list of validation check items for a signature (integrity, cryptographic, identity, revocation, timestamp, algorithm, chain, EKU). Used by the ValidityChecklist component.
function buildChecks(sig: PdfSignature): CheckItem[]buildMiniChecks(sig)
Builds compact check items for the signature list panel (integrity, cryptographic, identity, revocation, timestamp).
function buildMiniChecks(sig: PdfSignature): MiniCheckItem[]buildSummaryLines(sig)
Builds Adobe-style summary lines for the signature list panel expanded section (integrity, identity, timestamp, LTV status).
function buildSummaryLines(sig: PdfSignature): SummaryLine[]isLtvEnabled(sig)
Returns true if the signature is LTV-enabled (has a verified timestamp and valid revocation data).
function isLtvEnabled(sig: PdfSignature): booleanCertificate Utilities
DN (Distinguished Name) parsing utilities shared across signature, certificate, and panel components.
getCN(s)
Extract the Common Name (CN) from a DN string. Falls back to the full string if CN is not found.
function getCN(s: string): stringgetO(s)
Extract the Organization (O) from a DN string. Returns empty string if not found.
function getO(s: string): stringgetField(s, key)
Extract any RDN field from a DN string by key (e.g. 'OU', 'C', 'L').
function getField(s: string, key: string): stringFormat Utilities
Date formatting utilities for UI display. All functions accept Date | string defensively, handling ISO strings from rehydration.
fmtDateLong(d)
Full datetime with weekday. Used in signature detail views.
function fmtDateLong(d: Date | string): string
// Example: "Saturday, March 15, 2025, 02:30:45 PM UTC"fmtDateShort(d)
Short datetime. Used in certificate viewer tables and timestamp details.
function fmtDateShort(d: Date | string): string
// Example: "Mar 15, 2025, 02:30:45 PM UTC"fmtDateCompact(d)
Compact datetime without seconds. Used in the signature list panel. Returns empty string for null/undefined.
function fmtDateCompact(d: Date | string | null | undefined): string
// Example: "Mar 15, 2025, 14:30"fmtDatePanel(d)
Panel datetime with seconds in 24h format. Used in Adobe-style signature list panel. Returns empty string for null/undefined.
function fmtDatePanel(d: Date | string | null | undefined): string
// Example: "Mar 15, 2025, 14:30:45 UTC"Download & Export Utilities
Certificate export and file download utilities. SSR-safe: browser-only APIs are guarded. These functions are only called from click handlers, never during render.
uint8ToBase64(bytes)
Convert a Uint8Array to a base64 string. Works in both browser (via btoa) and Node.js (via Buffer).
function uint8ToBase64(bytes: Uint8Array): stringdownloadBlob(blob, name)
Trigger a browser file download for a Blob with the given filename.
function downloadBlob(blob: Blob, name: string): voidexportCertAsPem(cert, filename)
Export a certificate as a PEM file. Downloads a .pem file if the certificate has raw DER data.
function exportCertAsPem(cert: CertificateInfo, filename: string): voidexportCertAsDer(cert, filename)
Export a certificate as a DER file. Downloads a .cer file if the certificate has raw DER data.
function exportCertAsDer(cert: CertificateInfo, filename: string): voidsafeName(cert)
Generate a filesystem-safe filename from a certificate's Common Name. Replaces non-alphanumeric characters with underscores.
function safeName(cert: CertificateInfo): stringAppearance Swapper
Functions for modifying signature appearance XObject layers in-memory to reflect verification results. Called after verifyPdf() on the original bytes -- the returned bytes are used only for PDF.js display.
swapSignatureAppearances(pdfBytes, signatures)
Swap signature appearance XObject layers to show verification status icons (checkmark, cross, question mark). Supports both legacy (n1 layer) and Acro6 (FRM/n0 layer) signature structures.
async function swapSignatureAppearances(
pdfBytes: Uint8Array,
signatures: PdfSignature[],
): Promise<Uint8Array>| Parameter | Type | Description |
|---|---|---|
pdfBytes | Uint8Array | Original PDF bytes (unmodified) |
signatures | PdfSignature[] | Verified signatures with overallStatus populated |
Returns: Modified PDF bytes for display, or the original bytes if swapping is not possible.
hasAcro6Appearances(pdfBytes)
Lightweight read-only check: does this PDF have any signature widgets with Acro6 layer structure (no /n1, has /FRM or /n0)?
async function hasAcro6Appearances(pdfBytes: Uint8Array): Promise<boolean>Recent Files
Recent files persistence via localStorage. SSR-safe: all localStorage calls are guarded.
RecentFileEntry
interface RecentFileEntry {
fileName: string
fileSize: number
lastOpened: string // ISO date string
signatureCount?: number
overallStatus?: string
}loadRecentFiles()
Load the list of recent files from localStorage. Returns an empty array on the server or if no data exists.
function loadRecentFiles(): RecentFileEntry[]addRecentFile(entry)
Add a file to the recent files list. Deduplicates by filename, prepends the new entry, and trims to 8 entries max.
function addRecentFile(entry: RecentFileEntry): RecentFileEntry[]clearRecentFiles()
Remove all recent files from localStorage.
function clearRecentFiles(): RecentFileEntry[]CoreViewer & Viewer Components
<CoreViewer>
The minimal PDF viewer engine. Manages PDF.js document loading, page rendering, store creation, plugin lifecycle, and layout composition. <Viewer> is a thin wrapper around this component.
<CoreViewer
ref={viewerRef}
fileBuffer={buffer}
fileName="report.pdf"
plugins={[layout.plugin]}
onDocumentLoaded={(doc) => console.log(doc.numPages)}
renderError={(err) => <MyErrorUI error={err} />}
/>Props (CoreViewerProps):
| Prop | Type | Required | Description |
|---|---|---|---|
fileBuffer | ArrayBuffer | null | No | PDF file bytes |
fileName | string | No | File name for display |
plugins | ViewerPlugin[] | No | Plugins to install |
initialState | Partial<ViewerStoreState> | No | Initial viewer state overrides |
signatures | PdfSignature[] | No | Reactive signature data (synced to store) |
unsignedFields | UnsignedSigField[] | No | Reactive unsigned field data |
verificationStatus | VerificationStatus | No | Reactive overall verification status |
signaturePanelOpen | boolean | No | Whether the signature panel should initially be open |
onDocumentLoaded | (doc: PDFDocumentProxy) => void | No | Called when document is loaded |
onPageCountChange | (n: number) => void | No | Called when page count is known |
onReady | () => void | No | Called when viewer is ready |
renderError | (error: LoadError) => ReactNode | No | Custom error renderer |
onLoadError | (error: LoadError) => void | No | Called when a document load error occurs |
renderLayout | (slots: CoreViewerSlots) => ReactNode | No | Custom layout render function |
onContextMenu | (e: React.MouseEvent) => void | No | Right-click handler |
onOpenFile | (file: File) => void | No | File open handler (enables drag-drop) |
isActive | boolean | No | Tab isolation -- disable global listeners when hidden (default: true) |
verifying | boolean | No | True while verification is in progress (controls VerificationFloater) |
CoreViewerHandle
Ref handle exposed by the <CoreViewer> component.
interface CoreViewerHandle {
scrollToPage(n: number): void
getStore(): ViewerStore
}CoreViewerSlots
Layout slot objects passed to the renderLayout callback for full custom layout control.
interface CoreViewerSlots {
/** Toolbar area content from plugins */
toolbar: React.ReactNode
/** Sidebar area content from plugins */
sidebar: React.ReactNode
/** The scrollable page area */
pages: React.ReactNode
/** Overlays (findbar, message bar, etc.) */
overlays: React.ReactNode[]
/** All resolved toolbar slots */
toolbarSlots: ToolbarSlots
/** All resolved sidebar tabs */
sidebarTabs: SidebarTabDefinition[]
}<PageRenderer>
Renders a single PDF page with canvas, text layer, and annotation layer. Lazy-rendered via IntersectionObserver. HiDPI-aware canvas rendering (capped at 3x device pixel ratio).
interface PageRendererProps {
page: PDFPageProxy
scale: number
rotation: 0 | 90 | 180 | 270
pageNum: number
totalPages: number
linkService: any
/** Additional overlays (signature widgets, highlights, etc.) */
children?: React.ReactNode
}Store Infrastructure
createViewerStore(overrides?)
Factory function that creates a new ViewerStore instance. The store is a lightweight pub-sub reactive state container that drives the viewer.
function createViewerStore(overrides?: Partial<ViewerStoreState>): ViewerStoreExample:
const store = createViewerStore({ scale: 1.5, themeMode: 'dark' })
store.get('scale') // 1.5
store.update({ scale: 2 })
store.subscribe('scale', (newVal, oldVal) => console.log(newVal))INITIAL_STATE
The default initial state for a ViewerStore. Can be used as a reference or for resetting state.
const INITIAL_STATE: ViewerStoreState = {
document: null,
fileBuffer: null,
originalFileBuffer: null,
fileName: '',
loadState: 'idle',
loadError: null,
currentPage: 1,
totalPages: 0,
scale: 1.2,
fitMode: 'none',
rotation: 0,
scrollMode: 'vertical',
spreadMode: 'none',
cursorTool: 'select',
themeMode: 'light',
uiFontScale: 'default',
isFullscreen: false,
signatures: [],
unsignedFields: [],
verificationStatus: null,
sidebarOpen: false,
sidebarTab: 'thumbnails',
sigPanelOpen: false,
findOpen: false,
propertiesModalOpen: false,
shortcutHelpOpen: false,
contextMenuPos: null,
sigModalIndex: null,
sigModalFieldName: '',
sigModalTab: 'details',
passwordNeeded: false,
passwordError: false,
}ViewerStoreContext
React context that provides the ViewerStore instance. Created by <CoreViewer> / <Viewer> and consumed by useViewerStore() and related hooks.
const ViewerStoreContext: React.Context<ViewerStore | null>Store Actions
Shared viewer store action functions that eliminate duplicate logic across plugins and menu components. SSR-safe: all browser API calls are guarded.
downloadPdf(store)
Download the PDF. Prefers the original unmodified bytes over appearance-swapped bytes.
function downloadPdf(store: ViewerStore): voidrotateCW(store)
Rotate the document clockwise by 90 degrees.
function rotateCW(store: ViewerStore): voidrotateCCW(store)
Rotate the document counter-clockwise by 90 degrees.
function rotateCCW(store: ViewerStore): voidtoggleFullscreen(store, element?)
Toggle fullscreen on the given element (falls back to document root).
function toggleFullscreen(store: ViewerStore, element?: HTMLElement | null): voidPlugin Host Functions
Internal infrastructure for managing plugin lifecycle and collecting UI contributions. Useful for advanced custom viewer implementations.
resolvePlugins(plugins)
Flatten composedPlugins and deduplicate by name. Validates that all declared dependencies are present.
function resolvePlugins(plugins: ViewerPlugin[]): ViewerPlugin[]collectToolbarSlots(plugins)
Merge toolbar slot contributions from all plugins, then apply any transformToolbarSlots transforms.
function collectToolbarSlots(plugins: ViewerPlugin[]): ToolbarSlotscollectSidebarTabs(plugins)
Collect sidebar tab definitions from all plugins, sorted by order.
function collectSidebarTabs(plugins: ViewerPlugin[]): SidebarTabDefinition[]Individual Plugin APIs
Each plugin factory function returns a ViewerPlugin & { api: <ApiType> }. Access the API via the .api property. When using defaultLayoutPlugin(), sub-plugin APIs are available directly on the result object.
ZoomPluginApi
interface ZoomPluginApi {
zoomIn(): void
zoomOut(): void
zoomTo(scale: number): void
setFitMode(mode: 'none' | 'width' | 'page'): void
}PageNavigationPluginApi
interface PageNavigationPluginApi {
goToPage(n: number): void
goToPreviousPage(): void
goToNextPage(): void
goToFirstPage(): void
goToLastPage(): void
}RotationPluginApi
interface RotationPluginApi {
rotateCW(): void
rotateCCW(): void
setRotation(r: 0 | 90 | 180 | 270): void
}SearchPluginApi
interface SearchPluginApi {
open(): void
close(): void
toggle(): void
}PrintPluginApi
interface PrintPluginApi {
print(): void
}DownloadPluginApi
interface DownloadPluginApi {
download(): void
}ThemePluginApi
interface ThemePluginApi {
toggleTheme(): void
setTheme(mode: 'light' | 'dark'): void
getTheme(): 'light' | 'dark'
}FullscreenPluginApi
interface FullscreenPluginApi {
enterFullscreen(): void
exitFullscreen(): void
toggleFullscreen(): void
}SelectionPluginApi
interface SelectionPluginApi {
setCursorTool(tool: 'select' | 'hand'): void
toggleHand(): void
}ScrollModePluginApi
interface ScrollModePluginApi {
setScrollMode(mode: 'vertical' | 'horizontal' | 'wrapped' | 'page'): void
}SpreadModePluginApi
interface SpreadModePluginApi {
setSpreadMode(mode: 'none' | 'odd' | 'even'): void
}SignaturePluginApi
interface SignaturePluginApi {
openPanel(): void
closePanel(): void
togglePanel(): void
}SidebarPluginApi
interface SidebarPluginApi {
open(tabId?: string): void
close(): void
toggle(tabId?: string): void
setTab(tabId: string): void
}AccessibilityPluginApi
interface AccessibilityPluginApi {
setFontScale(scale: 'compact' | 'default' | 'large' | 'extra-large'): void
getFontScale(): 'compact' | 'default' | 'large' | 'extra-large'
}DefaultLayoutPluginOptions
interface DefaultLayoutPluginOptions {
accessibility?: AccessibilityPluginOptions
toolbar?: ToolbarPluginOptions
disable?: {
search?: boolean
print?: boolean
download?: boolean
fullscreen?: boolean
theme?: boolean
rotation?: boolean
selection?: boolean
sidebar?: boolean
signatures?: boolean
highlights?: boolean
openFile?: boolean
properties?: boolean
shortcuts?: boolean
contextMenu?: boolean
accessibility?: boolean
}
}
interface AccessibilityPluginOptions {
initialScale?: 'compact' | 'default' | 'large' | 'extra-large'
persist?: boolean // default: true — save preference to localStorage
}DefaultLayoutPluginResult
interface DefaultLayoutPluginResult {
plugin: ViewerPlugin
zoom: ZoomPluginApi
navigation: PageNavigationPluginApi
rotation: RotationPluginApi
search: SearchPluginApi
print: PrintPluginApi
download: DownloadPluginApi
theme: ThemePluginApi
fullscreen: FullscreenPluginApi
selection: SelectionPluginApi
scrollMode: ScrollModePluginApi
spreadMode: SpreadModePluginApi
signature: SignaturePluginApi
sidebar: SidebarPluginApi
accessibility: AccessibilityPluginApi
}UI Primitives
Dialog Components
Portal-based modal dialog built on Radix UI Dialog. Renders at the document root with position: fixed.
// Root dialog container (controls open/close state)
const Dialog: React.FC<RadixDialogProps>
// Semi-transparent backdrop overlay
const DialogOverlay: React.ForwardRefComponent<HTMLDivElement>
// Centered dialog content panel (includes overlay automatically)
const DialogContent: React.ForwardRefComponent<HTMLDivElement>
// Dialog title heading
const DialogTitle: React.ForwardRefComponent<HTMLHeadingElement>
// Flexbox column container for dialog header area
const DialogHeader: React.FC<React.HTMLAttributes<HTMLDivElement>>
// Close button (triggers onOpenChange(false))
const DialogClose: React.FC<RadixDialogCloseProps>Example:
import { Dialog, DialogContent, DialogTitle, DialogHeader, DialogClose } from '@trexolab/verifykit-react'
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent style={{ maxWidth: 480 }}>
<DialogHeader>
<DialogTitle>Certificate Details</DialogTitle>
</DialogHeader>
<p>Dialog body content</p>
<DialogClose>Close</DialogClose>
</DialogContent>
</Dialog>ViewerDialog Components
Inline modal that renders inside the viewer container with position: absolute. Unlike the portal-based Dialog, these stay within the viewer bounds and work correctly when the viewer is embedded. Features backdrop blur, escape-to-close, and focus management.
// Root dialog wrapper (absolute positioned within viewer)
function ViewerDialog(props: {
open: boolean
onOpenChange?: (open: boolean) => void
children: React.ReactNode
}): React.ReactNode
// Blurred backdrop overlay (covers only the viewer area)
function ViewerDialogOverlay(props: {
onClick?: () => void
}): React.ReactNode
// Centered content panel with border, shadow, and entrance animation
function ViewerDialogContent(props: {
children: React.ReactNode
style?: React.CSSProperties
onClose?: () => void
}): React.ReactNode
// Dialog title heading (h2 element)
function ViewerDialogTitle(props: {
children: React.ReactNode
style?: React.CSSProperties
}): React.ReactNodeToolbar Components
<Toolbar>
Three-section grid layout toolbar (LEFT | CENTER | RIGHT) that renders named slots contributed by plugins.
function Toolbar(props: { slots: ToolbarSlots; store: ViewerStore }): React.ReactNode<ToolbarButton>
Shared toolbar button primitive with tooltip, active state, and badge support.
| Prop | Type | Required | Description |
|---|---|---|---|
icon | React.ReactNode | Yes | Button icon |
onClick | () => void | Yes | Click handler |
disabled | boolean | No | Disabled state |
title | string | No | Tooltip text |
shortcut | string | No | Keyboard shortcut hint in tooltip |
active | boolean | No | Active/pressed state |
badge | number | No | Notification badge count |
ariaExpanded | boolean | No | ARIA expanded state |
ariaHasPopup | boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | No | ARIA popup indicator |
<ToolbarDivider>
Visual separator line between toolbar button groups.
function ToolbarDivider(): React.ReactNodeToolbarPluginOptions
Options for the toolbar plugin. Allows transforming toolbar slots to add, remove, or reorder controls.
interface ToolbarPluginOptions {
/** Transform toolbar slots -- add, remove, or reorder */
transform?: (slots: ToolbarSlots) => ToolbarSlots
}i18n (Internationalization)
Built-in Locales
The following locale is built-in with full translations:
| Locale | Language |
|---|---|
'en' | English (default) |
Additional locales ('fr', 'de', 'es', 'ar', 'ja', 'zh') can be registered via registerLocale().
Locale
type Locale = 'en' | 'fr' | 'de' | 'es' | 'ar' | 'ja' | 'zh' | stringTranslationStrings
Interface defining all translatable string keys. Keys are organized by category:
| Category | Key prefix | Example keys |
|---|---|---|
| Toolbar | toolbar.* | toolbar.openFile, toolbar.zoomIn, toolbar.print |
| Status | status.* | status.valid, status.invalid, status.warning |
| Signature panel | panel.* | panel.signatures, panel.noSignatures |
| Document | document.* | document.properties, document.metadata |
| Find bar | find.* | find.placeholder, find.noResults |
| Welcome | welcome.* | welcome.title, welcome.subtitle |
| Password | password.* | password.title, password.submit |
| Verification | verification.* | verification.checking, verification.complete |
| PAdES | pades.* | pades.B-B, pades.B-T, pades.B-LT, pades.B-LTA |
| General | general.* | general.close, general.cancel, general.ok |
t(key, locale?)
Translate a key. Falls back to English, then to the key itself.
function t(key: string, locale?: string): stringsetLocale(locale) / getLocale()
Set or get the current active locale.
function setLocale(locale: string): void
function getLocale(): stringregisterLocale(locale, strings)
Register a custom locale or override strings for an existing locale.
function registerLocale(locale: string, strings: Partial<TranslationStrings>): voidExample:
import { registerLocale, setLocale } from '@trexolab/verifykit-react'
registerLocale('fr', {
'toolbar.print': 'Imprimer',
'toolbar.download': 'Telecharger',
'status.valid': 'Valide',
'status.invalid': 'Invalide',
})
setLocale('fr')getAvailableLocales()
Get all registered locale codes.
function getAvailableLocales(): string[]