React Integration
@trexolab/verifykit-react provides a React PDF viewer with signature verification, a plugin architecture, and theme support. It uses @trexolab/verifykit-core for cryptographic verification, powered by a Rust/WASM engine.
Setup
Install
npm install @trexolab/verifykit-react
pdfjs-distis included as a direct dependency and installs automatically.
Requirements: React 19+, modern browser with WebAssembly support. The workerUrl option is required in VerifyKitProvider config.
Import CSS
Add the stylesheet import at the top of your entry file:
import '@trexolab/verifykit-react/styles.css'Without this import, the viewer renders as a blank white area.
Copy CMap and Font Files
For non-Latin text support (CJK, Arabic, etc.), copy the CMap and font files to your public directory:
cp -r node_modules/pdfjs-dist/cmaps public/cmaps
cp -r node_modules/pdfjs-dist/standard_fonts public/standard_fontsAdd CSS Reset
html, body, #root {
height: 100%;
margin: 0;
padding: 0;
}Wrap with VerifyKitProvider
import { VerifyKitProvider } from '@trexolab/verifykit-react'
function App() {
return (
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: { mode: 'system' },
}}>
<div style={{ height: '100vh' }}>
<MyViewer />
</div>
</VerifyKitProvider>
)
}VerifyKitProvider
The provider wraps your app to supply configuration, verifier instance, theme, and i18n context. It handles WASM initialization internally -- no setup code needed.
<VerifyKitProvider config={config}>
<App />
</VerifyKitProvider>Configuration
interface VerifyKitConfig extends VerifyKitCoreConfig {
workerUrl: string // REQUIRED. URL to the PDF.js worker script.
cMapUrl?: string // Default: '/cmaps/'
standardFontDataUrl?: string // Default: '/standard_fonts/'
theme?: {
mode?: 'light' | 'dark' | 'system'
overrides?: Record<string, string> // CSS variable overrides
}
embeddedFont?: boolean | string
toolbar?: ToolbarConfig
locale?: string // Default: 'en'
translations?: Partial<TranslationStrings>
}Key options:
workerUrl-- Required. URL to the PDF.js worker script. Use'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs'for CDN, or self-host the file and pass a local path like'/pdf.worker.min.mjs'.theme.mode-- Set the initial theme to'light','dark', or'system'(follows OS preference).cMapUrl/standardFontDataUrl-- Paths to CMap and font files for non-Latin text.toolbar-- Configure which toolbar features are enabled.
useVerification Hook
The useVerification() hook manages PDF loading, verification, and result state. It creates an async verifier backed by the Rust/WASM core.
const verification = useVerification()
// Load a file (File, ArrayBuffer, Uint8Array, or URL)
await verification.load(file)
// Access results
verification.fileBuffer // ArrayBuffer | null — the loaded PDF bytes
verification.originalFileBuffer // ArrayBuffer | null — original file bytes (before appearance swap)
verification.fileName // string — display name of the loaded file
verification.signatures // PdfSignature[] — all verified signatures
verification.status // 'valid' | 'invalid' | 'warning' | 'unknown' | 'pending' | null
verification.unsignedFields // UnsignedSigField[] — unsigned signature fields
verification.isLoading // boolean — true while verification is in progress
verification.error // LoadError | null — error object if verification failed
verification.result // VerificationResult | null — full verification result object
verification.metadata // DocumentMetadata | null — PDF document metadata
verification.permissions // DocumentPermissions | null — PDF security permissions
// Re-verify all signatures on the current buffer
await verification.revalidate()
// Reset state
verification.reset()Key concept: Verification vs Viewer
VerifyKit separates two concerns:
| Concern | Responsibility | Component |
|---|---|---|
| Verification | Cryptographic signature validation via Rust/WASM | useVerification() hook |
| Viewer | PDF rendering and UI features | <Viewer> component with plugins |
The <Viewer> does not perform verification -- it only displays pre-verified results. useVerification() loads the PDF, runs all cryptographic checks, and produces results that you pass to the viewer as props.
Viewer Component
The <Viewer> is the recommended component for displaying PDFs. It accepts plugins for composable features.
<Viewer
ref={viewerRef}
fileBuffer={verification.fileBuffer}
fileName={verification.fileName}
plugins={[layout.plugin]}
onOpenFile={handleFile}
signatures={verification.signatures}
unsignedFields={verification.unsignedFields}
verificationStatus={verification.status ?? undefined}
/>Props
| Prop | Type | Description |
|---|---|---|
fileBuffer | ArrayBuffer | null | PDF file bytes |
fileName | string | Display name |
plugins | ViewerPlugin[] | Plugins to install |
signatures | PdfSignature[] | Reactive signature data (synced to store) |
unsignedFields | UnsignedSigField[] | Reactive unsigned field data |
verificationStatus | VerificationStatus | Reactive overall verification status |
verifying | boolean | Show a loading indicator while verification is in progress |
initialState | Partial<ViewerStoreState> | Initial store overrides (for advanced use) |
onDocumentLoaded | (doc) => void | Called when PDF.js document is ready |
onOpenFile | (file) => void | File open handler (enables drag-and-drop) |
onLoadError | (error: LoadError) => void | Called when the PDF fails to load |
onRevalidate | () => void | Called when user requests re-verification |
signaturePanelOpen | boolean | Auto-open the signature panel |
isActive | boolean | Tab isolation — set to false to freeze state updates |
renderError | (error: LoadError) => ReactNode | Custom error UI renderer |
renderLayout | (slots) => ReactNode | Custom layout render function |
Ref Handle
const viewerRef = useRef<ViewerHandle>(null)
viewerRef.current.scrollToPage(5)Plugins
Viewer features are provided by plugins. You compose only the plugins you need.
Batteries-Included (defaultLayoutPlugin)
The simplest approach -- all features with zero configuration:
import { defaultLayoutPlugin } from '@trexolab/verifykit-react'
function MyViewer() {
const [layout] = useState(() => defaultLayoutPlugin())
return <Viewer fileBuffer={buffer} plugins={[layout.plugin]} />
}Always wrap plugin creation in
useStateto avoid infinite re-renders. Creating a plugin inside the render body withoutuseStateproduces a new instance every render.
Selective Features
Disable specific features you do not need:
const [layout] = useState(() =>
defaultLayoutPlugin({
disable: { print: true, download: true, contextMenu: true },
})
)Individual Plugins
For maximum control, import and compose individual plugins:
import { zoomPlugin, pageNavigationPlugin, toolbarPlugin } from '@trexolab/verifykit-react'
const [zoom] = useState(() => zoomPlugin())
const [nav] = useState(() => pageNavigationPlugin())
const [toolbar] = useState(() => toolbarPlugin())
<Viewer fileBuffer={buffer} plugins={[zoom, nav, toolbar]} />See the Plugins guide for a complete list of all 24 plugins with their APIs and options.
WelcomeScreen
A file open/drop landing screen shown before a PDF is loaded:
import { WelcomeScreen } from '@trexolab/verifykit-react'
if (!verification.fileBuffer) {
return <WelcomeScreen onOpenFile={handleFile} />
}The WelcomeScreen displays a drop zone where users can drag and drop PDF files or click to browse. Pass onOpenFile to receive the selected File object. The accept prop controls which file types are shown in the file picker (default: '.pdf,application/pdf').
Theme Configuration
Theme Modes
Set the theme via the provider config:
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: { mode: 'system' },
}}>Available modes:
'light'-- Light theme'dark'-- Dark theme'system'-- Follows the operating system preference
CSS Variable Overrides
Override CSS variables through the provider config:
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: {
mode: 'dark',
overrides: {
'--primary': '#6366f1',
'--primary-hover': '#4f46e5',
},
},
}}>Runtime Theme Toggle
When using defaultLayoutPlugin, you can toggle the theme programmatically:
const [layout] = useState(() => defaultLayoutPlugin())
// Toggle between light and dark
layout.theme.toggleTheme()
// Set explicitly
layout.theme.setTheme('dark')Common Patterns
Full Example: File Loading and Verification
import { useState, useCallback, useRef } from 'react'
import {
VerifyKitProvider,
Viewer,
WelcomeScreen,
useVerification,
defaultLayoutPlugin,
} from '@trexolab/verifykit-react'
import '@trexolab/verifykit-react/styles.css'
function App() {
return (
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: { mode: 'system' },
}}>
<div style={{ height: '100vh' }}>
<MyViewer />
</div>
</VerifyKitProvider>
)
}
function MyViewer() {
const verification = useVerification()
const viewerRef = useRef(null)
const [layout] = useState(() => defaultLayoutPlugin())
const handleFile = useCallback(
(file) => { verification.load(file) },
[verification],
)
if (!verification.fileBuffer) {
return <WelcomeScreen onOpenFile={handleFile} />
}
return (
<Viewer
ref={viewerRef}
fileBuffer={verification.fileBuffer}
fileName={verification.fileName}
plugins={[layout.plugin]}
onOpenFile={handleFile}
signatures={verification.signatures}
unsignedFields={verification.unsignedFields}
verificationStatus={verification.status ?? undefined}
/>
)
}Subscribing to Viewer State
Use useViewerStore inside a component rendered within <Viewer> to subscribe to reactive state:
import { useViewerStore, useViewerStoreKey } from '@trexolab/verifykit-react'
// Select multiple values
const [page, total] = useViewerStore(s => [s.currentPage, s.totalPages])
// Select a single key
const scale = useViewerStoreKey('scale')Next.js Setup
VerifyKit works with Next.js 14+ but requires client-side rendering. All components use browser APIs (canvas, DOM, Web Workers, WebAssembly) and cannot run as Server Components.
// components/PdfViewer.tsx
'use client'
import { useState, useCallback, useRef } from 'react'
import { VerifyKitProvider, Viewer, WelcomeScreen, useVerification, defaultLayoutPlugin } from '@trexolab/verifykit-react'
import '@trexolab/verifykit-react/styles.css'
// ... viewer componentIf you encounter SSR errors, wrap with next/dynamic:
import dynamic from 'next/dynamic'
const PdfViewer = dynamic(() => import('@/components/PdfViewer'), { ssr: false })If you see a canvas module error, add to next.config.js:
const nextConfig = {
webpack: (config) => { config.resolve.alias.canvas = false; return config },
}Keyboard Shortcuts
The following shortcuts are available when using defaultLayoutPlugin:
| Shortcut | Action | Plugin |
|---|---|---|
Ctrl+= / Ctrl++ | Zoom in | zoomPlugin |
Ctrl+- | Zoom out | zoomPlugin |
Ctrl+0 | Fit page | zoomPlugin |
PageDown / N / J | Next page | pageNavigationPlugin |
PageUp / P / K | Previous page | pageNavigationPlugin |
R / Shift+R | Rotate CW / CCW | rotationPlugin |
Ctrl+F | Open search | searchPlugin |
Ctrl+P | printPlugin | |
Ctrl+S | Download | downloadPlugin |
F5 | Fullscreen | fullscreenPlugin |
H / S | Hand / Select tool | selectionPlugin |
? | Keyboard shortcuts help | shortcutHelpPlugin |
Other Components
| Component | Description |
|---|---|
<PdfViewer> | Legacy full-featured viewer with all features built-in. Still fully supported but not extensible via plugins. |
<PasswordDialog> | Password prompt for encrypted PDFs |
<DocumentMessageBar> | Top status bar showing verification result |
<SignatureListPanel> | Side panel listing all signatures |
<SignaturePropertiesModal> | Tabbed signature details modal (includes a PAdES tab for ETSI signatures) |
<CertificateViewer> | Certificate chain tree viewer |
i18n
The React package exports translation utilities for internationalization:
import { t, setLocale, registerLocale } from '@trexolab/verifykit-react'
// Get a translated string
const label = t('signature.valid')
// Switch locale at runtime
setLocale('fr')
// Register a custom locale
registerLocale('fr', { 'signature.valid': 'Signature valide', /* ... */ })You can also pass locale and translations via the VerifyKitProvider config for initial setup.