Customization
This guide covers theming, CSS variable overrides, toolbar configuration, feature flags, and worker setup.
Theme Modes
VerifyKit supports three theme modes: 'light', 'dark', and 'system'.
React
Set the theme via the VerifyKitProvider config:
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: { mode: 'system' },
}}>
<App />
</VerifyKitProvider>Toggle the theme at runtime using the defaultLayoutPlugin API:
const [layout] = useState(() => defaultLayoutPlugin())
layout.theme.toggleTheme() // Toggle between light and dark
layout.theme.setTheme('dark') // Set explicitlyVanilla JS
Set the theme at creation time or change it later:
const viewer = VerifyKit.create(el, {
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
theme: { mode: 'system' },
})
// Change at runtime
viewer.setTheme('dark')Listen for theme changes:
viewer.on('themeChange', (mode) => {
console.log('Theme changed to:', mode)
})CSS Variables
VerifyKit's appearance is controlled by CSS custom properties defined on :root. You can override any variable to customize the look and feel.
Overriding via Provider Config
Pass CSS variable overrides through the theme configuration:
<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',
},
},
}}>Overriding via CSS
You can also override variables in your own stylesheet:
:root {
--primary: #6366f1;
--primary-hover: #4f46e5;
--toolbar-bg: #1a1a2e;
}Key Variable Categories
Layout
| Variable | Default | Description |
|---|---|---|
--toolbar-height | 42px | Height of the toolbar |
--left-nav-width | 36px | Width of the left navigation bar |
--btn-size | 30px | Standard button size |
Colors — Surfaces
| Variable | Light | Dark | Description |
|---|---|---|---|
--surface-1 | #ffffff | #1e1e1e | Primary surface background |
--surface-2 | #f5f5f5 | #252525 | Secondary surface background |
--surface-3 | #ececec | #2d2d2d | Tertiary surface background |
--doc-area-bg | #e8e8e8 | #383838 | Document area background |
Colors — Typography
| Variable | Light | Dark | Description |
|---|---|---|---|
--fg | #1a1a1a | #e0e0e0 | Primary text color |
--fg-secondary | #333333 | #cccccc | Secondary text color |
--fg-muted | #666666 | #999999 | Muted text color |
--fg-subtle | #999999 | #666666 | Subtle text color |
Accent / Interactive
| Variable | Light | Dark | Description |
|---|---|---|---|
--primary | #0072c6 | #0072c6 | Primary accent color |
--primary-hover | #005ea3 | #005ea3 | Accent hover state |
--primary-light | #e5f1fc | rgba(0,114,198,0.20) | Light accent tint |
--selected-bg | #ddeafa | rgba(0,114,198,0.25) | Selected item background |
--hover-bg | #eff5fe | rgba(255,255,255,0.07) | Hover background |
--focus-ring | rgba(0,114,198,0.45) | -- | Focus ring color |
Borders
| Variable | Light | Dark | Description |
|---|---|---|---|
--border | #e0e0e0 | #3c3c3c | Standard border |
--border-strong | #c4c4c4 | #555555 | Stronger border |
Toolbar
| Variable | Light | Dark | Description |
|---|---|---|---|
--toolbar-bg | #ffffff | #1d1d1d | Toolbar background |
--toolbar-border | #e0e0e0 | #0d0d0d | Toolbar border |
--toolbar-text | #555555 | rgba(255,255,255,0.55) | Toolbar text |
--toolbar-text-active | #0072c6 | rgba(255,255,255,0.95) | Active toolbar text |
--toolbar-hover | #f0f0f0 | rgba(255,255,255,0.08) | Toolbar hover |
Shadows
| Variable | Default (Light) | Description |
|---|---|---|
--shadow-xs | 0 1px 2px rgba(0,0,0,0.05) | Extra small shadow |
--shadow-sm | 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04) | Small shadow |
--shadow-md | 0 4px 12px rgba(0,0,0,0.10), 0 2px 4px rgba(0,0,0,0.06) | Medium shadow |
--shadow-lg | 0 8px 28px rgba(0,0,0,0.14), 0 4px 10px rgba(0,0,0,0.08) | Large shadow |
--shadow-xl | 0 20px 48px rgba(0,0,0,0.18), 0 8px 16px rgba(0,0,0,0.10) | Extra large shadow |
--shadow-page | 0 1px 4px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.08) | Page shadow |
Semantic Status Colors
| Variable | Light | Dark | Description |
|---|---|---|---|
--color-valid | #0d6b2c | #4ade80 | Valid/success color |
--color-invalid | #b83016 | #f87171 | Invalid/error color |
--color-warning | #975300 | #fbbf24 | Warning color |
--color-unknown | #5a6370 | #9ca3af | Unknown/neutral color |
Status Surfaces (used by signature panels and banners)
| Variable | Description |
|---|---|
--surface-valid | Background for valid status banners |
--surface-invalid | Background for invalid status banners |
--surface-warning | Background for warning/unknown status banners |
--surface-valid-border | Left stripe for valid signature cards |
--surface-invalid-border | Left stripe for invalid signature cards |
--surface-warning-border | Left stripe for warning/unknown signature cards |
--bar-valid-bg | Document message bar — valid |
--bar-invalid-bg | Document message bar — invalid |
--bar-warn-bg | Document message bar — warning |
--bar-unknown-bg | Document message bar — unknown |
Toolbar Configuration
React — defaultLayoutPlugin
Disable specific toolbar features using the disable option:
const [layout] = useState(() =>
defaultLayoutPlugin({
disable: {
search: true,
print: true,
download: true,
rotation: true,
fullscreen: true,
theme: true,
selection: true,
openFile: true,
contextMenu: true,
properties: true,
shortcuts: true,
},
})
)React — Individual Plugins
For maximum control, compose only the plugins you want:
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]} />This gives you a minimal viewer with only zoom and page navigation -- no search, no print, no sidebar.
Feature Flags
Vanilla JS
The vanilla API exposes features as a flat configuration object. Each feature can be individually toggled:
const viewer = VerifyKit.create(el, {
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
features: {
search: true, // default: true
print: true, // default: true
download: false, // default: false
signatures: true, // default: true
thumbnails: true, // default: true
fullscreen: true, // default: true
themeToggle: true, // default: true
openFile: false, // default: false
rotation: true, // default: true
contextMenu: true, // default: true
properties: true, // default: true
shortcuts: true, // default: true
highlights: true, // default: true
},
})Internally, feature flags are mapped to defaultLayoutPlugin({ disable: {...} }).
Accessibility
UI Font Scale
VerifyKit includes a built-in UI font scale control that lets users adjust the size of all viewer text, toolbar buttons, and panel elements. This is an accessibility feature similar to browser zoom, but scoped to the viewer only.
A toolbar dropdown (Aa icon) is included by default. Users can choose from four presets:
| Scale | Multiplier | Base Font | Toolbar Height | Button Size |
|---|---|---|---|---|
| Compact | 0.88x | 11.4px | 31.7px | 22.9px |
| Default | 1.00x | 13.0px | 36.0px | 26.0px |
| Large | 1.15x | 15.0px | 41.4px | 29.9px |
| Extra Large | 1.30x | 16.9px | 46.8px | 33.8px |
The user's preference is automatically saved to localStorage and restored on subsequent visits.
React
// Set initial scale via defaultLayoutPlugin
const [layout] = useState(() =>
defaultLayoutPlugin({
accessibility: { initialScale: 'large' },
})
)
// Programmatic control
layout.accessibility.setFontScale('extra-large')
layout.accessibility.getFontScale() // 'extra-large'
// Disable the feature entirely
defaultLayoutPlugin({
disable: { accessibility: true },
})Vanilla JS
const viewer = VerifyKit.create(el, {
workerUrl: '...',
features: { accessibility: true }, // default: true
})
viewer.setFontScale('large')
viewer.getFontScale() // 'large'
// Listen for changes
viewer.on('fontScaleChange', (scale) => {
console.log('Font scale changed to:', scale)
})Standalone Plugin
import { accessibilityPlugin } from '@trexolab/verifykit-react'
const a11y = accessibilityPlugin({
initialScale: 'large', // 'compact' | 'default' | 'large' | 'extra-large'
persist: true, // save to localStorage (default: true)
})
<Viewer plugins={[a11y, ...otherPlugins]} />
// API
a11y.api.setFontScale('extra-large')
a11y.api.getFontScale()CSS Variables
The font scale works by setting a data-font-scale attribute on .verifykit-root and overriding the CSS design token variables. You can customize the scale factors with CSS:
/* Custom scale overrides */
.verifykit-root[data-font-scale="large"] {
--ui-scale: 1.20; /* adjust from default 1.15 */
--font-base: calc(13px * 1.20);
--btn-size: calc(26px * 1.20);
--toolbar-height: calc(36px * 1.20);
}Worker Configuration
VerifyKit uses a Web Worker to render PDF pages off the main thread. The workerUrl option is required -- it specifies the URL to the PDF.js worker script.
CDN (Recommended)
Use the legacy worker from unpkg:
React:
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
}}>Vanilla JS:
const viewer = VerifyKit.create(el, {
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
})Self-Hosted Worker
Copy the worker file to your public directory and pass a local path:
cp node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs public/React:
<VerifyKitProvider config={{ workerUrl: '/pdf.worker.min.mjs' }}>Vanilla JS:
const viewer = VerifyKit.create(el, {
workerUrl: '/pdf.worker.min.mjs',
})Important: The worker version must match the pdfjs-dist version used by VerifyKit (5.5.207). Using a mismatched version will cause rendering errors.
CMap and Standard Font URLs
For non-Latin text support (CJK, Arabic, Hebrew, etc.), VerifyKit loads CMap and font files at runtime. Copy them to your public directory:
cp -r node_modules/pdfjs-dist/cmaps public/cmaps
cp -r node_modules/pdfjs-dist/standard_fonts public/standard_fontsCustomize the paths if you serve them from a different location:
<VerifyKitProvider config={{
workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
cMapUrl: '/assets/cmaps/',
standardFontDataUrl: '/assets/standard_fonts/',
}}>The defaults are /cmaps/ and /standard_fonts/.
Content Security Policy
If your application uses a strict CSP, you may need to add these directives:
Content-Security-Policy:
worker-src 'self' https://unpkg.com;
script-src 'self' 'wasm-unsafe-eval';
worker-src 'self' https://unpkg.com-- Required if using the CDN-hosted worker. If self-hosting the worker,worker-src 'self'is sufficient.script-src 'wasm-unsafe-eval'-- Required for WebAssembly compilation.
Signature Appearance Icons (Acro6)
VerifyKit swaps signature appearance icons in PDFs that use the Acro6 layer structure (common in Adobe-signed documents). The icons are auto-generated from SVG source files.
Source Files
packages/react/src/icons/acro6/
├── valid.svg # Green checkmark (valid signatures)
├── invalid.svg # Red cross (invalid signatures)
└── unknown.svg # Yellow question mark (unknown/warning)
Customizing Icons
- Edit the SVG file(s) in
packages/react/src/icons/acro6/ - Run the conversion script:
node packages/react/scripts/convert-acro6-icons.mjs - Build the package:
npm run build:react
The conversion script automatically:
- Parses SVG path commands (M, L, H, V, C, Z)
- Scales coordinates to fit the 100×100 PDF icon BBox
- Flips the Y-axis (SVG Y goes down, PDF Y goes up)
- Maps SVG fill/stroke colors to PDF color operators
- Handles
<rect>elements
The generated file src/icons/acro6-icons.generated.ts is auto-regenerated on every build (prebuild step).
How Appearance Swapping Works
After signature verification, swapSignatureAppearances() modifies the PDF's signature widget XObject layers to show the appropriate status icon:
- Legacy mode (has
/n1layer): Replaces the/n1content stream with the icon + updates/n4status text - Acro6 mode (has
/FRM+/n0): Blanks the original/n0(question-mark placeholder), injects the status icon into the FRM stream
import { swapSignatureAppearances, hasAcro6Appearances } from '@trexolab/verifykit-react'
// After verification
const result = await verifier.verify(pdfBytes)
const hasAcro6 = await hasAcro6Appearances(pdfBytes)
if (hasAcro6 || result.signatures.some(s => s.isVisible)) {
const modifiedPdf = await swapSignatureAppearances(pdfBytes, result.signatures)
// Use modifiedPdf for display in PDF.js
}Keyboard Shortcuts
VerifyKit includes built-in keyboard shortcuts for navigation, zoom, tools, and document actions.
Built-in Shortcuts
| Category | Shortcut | Action |
|---|---|---|
| Navigation | PageUp / P / K | Previous page |
PageDown / N / J | Next page | |
Home | First page | |
End | Last page | |
| Zoom | Ctrl+= | Zoom in |
Ctrl+- | Zoom out | |
Ctrl+0 | Fit page | |
Ctrl+1 | Actual size (100%) | |
Ctrl+2 | Fit width | |
| Tools | H | Toggle hand tool |
S | Toggle text select | |
| View | R | Rotate clockwise |
Shift+R | Rotate counter-clockwise | |
F5 | Toggle fullscreen | |
| Search | Ctrl+F | Toggle find bar |
F3 | Find next | |
| Actions | Ctrl+S | Download PDF |
Ctrl+P | ||
Ctrl+O | Open file | |
| Help | ? | Show keyboard shortcuts |
Tool shortcuts (H, S, Ctrl+F, F5) are toggles — press once to activate, press again to deactivate.
Registering Custom Shortcuts
Plugins can register additional shortcuts via the PluginContext:
function myPlugin(): ViewerPlugin {
return {
name: 'my-plugin',
install(ctx) {
ctx.registerShortcut({
id: 'my-action',
key: 'g',
ctrl: true,
description: 'Go to page',
handler(e) {
e.preventDefault()
// your action
},
})
},
}
}