VerifyKitv0.5.1

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:

tsx
<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:

tsx
const [layout] = useState(() => defaultLayoutPlugin())
 
layout.theme.toggleTheme()     // Toggle between light and dark
layout.theme.setTheme('dark')  // Set explicitly

Vanilla JS

Set the theme at creation time or change it later:

ts
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:

ts
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:

tsx
<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:

css
:root {
  --primary: #6366f1;
  --primary-hover: #4f46e5;
  --toolbar-bg: #1a1a2e;
}

Key Variable Categories

Layout

VariableDefaultDescription
--toolbar-height42pxHeight of the toolbar
--left-nav-width36pxWidth of the left navigation bar
--btn-size30pxStandard button size

Colors — Surfaces

VariableLightDarkDescription
--surface-1#ffffff#1e1e1ePrimary surface background
--surface-2#f5f5f5#252525Secondary surface background
--surface-3#ececec#2d2d2dTertiary surface background
--doc-area-bg#e8e8e8#383838Document area background

Colors — Typography

VariableLightDarkDescription
--fg#1a1a1a#e0e0e0Primary text color
--fg-secondary#333333#ccccccSecondary text color
--fg-muted#666666#999999Muted text color
--fg-subtle#999999#666666Subtle text color

Accent / Interactive

VariableLightDarkDescription
--primary#0072c6#0072c6Primary accent color
--primary-hover#005ea3#005ea3Accent hover state
--primary-light#e5f1fcrgba(0,114,198,0.20)Light accent tint
--selected-bg#ddeafargba(0,114,198,0.25)Selected item background
--hover-bg#eff5fergba(255,255,255,0.07)Hover background
--focus-ringrgba(0,114,198,0.45)--Focus ring color

Borders

VariableLightDarkDescription
--border#e0e0e0#3c3c3cStandard border
--border-strong#c4c4c4#555555Stronger border

Toolbar

VariableLightDarkDescription
--toolbar-bg#ffffff#1d1d1dToolbar background
--toolbar-border#e0e0e0#0d0d0dToolbar border
--toolbar-text#555555rgba(255,255,255,0.55)Toolbar text
--toolbar-text-active#0072c6rgba(255,255,255,0.95)Active toolbar text
--toolbar-hover#f0f0f0rgba(255,255,255,0.08)Toolbar hover

Shadows

VariableDefault (Light)Description
--shadow-xs0 1px 2px rgba(0,0,0,0.05)Extra small shadow
--shadow-sm0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04)Small shadow
--shadow-md0 4px 12px rgba(0,0,0,0.10), 0 2px 4px rgba(0,0,0,0.06)Medium shadow
--shadow-lg0 8px 28px rgba(0,0,0,0.14), 0 4px 10px rgba(0,0,0,0.08)Large shadow
--shadow-xl0 20px 48px rgba(0,0,0,0.18), 0 8px 16px rgba(0,0,0,0.10)Extra large shadow
--shadow-page0 1px 4px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.08)Page shadow

Semantic Status Colors

VariableLightDarkDescription
--color-valid#0d6b2c#4ade80Valid/success color
--color-invalid#b83016#f87171Invalid/error color
--color-warning#975300#fbbf24Warning color
--color-unknown#5a6370#9ca3afUnknown/neutral color

Status Surfaces (used by signature panels and banners)

VariableDescription
--surface-validBackground for valid status banners
--surface-invalidBackground for invalid status banners
--surface-warningBackground for warning/unknown status banners
--surface-valid-borderLeft stripe for valid signature cards
--surface-invalid-borderLeft stripe for invalid signature cards
--surface-warning-borderLeft stripe for warning/unknown signature cards
--bar-valid-bgDocument message bar — valid
--bar-invalid-bgDocument message bar — invalid
--bar-warn-bgDocument message bar — warning
--bar-unknown-bgDocument message bar — unknown

Toolbar Configuration

React — defaultLayoutPlugin

Disable specific toolbar features using the disable option:

tsx
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:

tsx
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:

ts
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:

ScaleMultiplierBase FontToolbar HeightButton Size
Compact0.88x11.4px31.7px22.9px
Default1.00x13.0px36.0px26.0px
Large1.15x15.0px41.4px29.9px
Extra Large1.30x16.9px46.8px33.8px

The user's preference is automatically saved to localStorage and restored on subsequent visits.

React

tsx
// 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

ts
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

tsx
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:

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.

Use the legacy worker from unpkg:

React:

tsx
<VerifyKitProvider config={{
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
}}>

Vanilla JS:

ts
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:

bash
cp node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs public/

React:

tsx
<VerifyKitProvider config={{ workerUrl: '/pdf.worker.min.mjs' }}>

Vanilla JS:

ts
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:

bash
cp -r node_modules/pdfjs-dist/cmaps public/cmaps
cp -r node_modules/pdfjs-dist/standard_fonts public/standard_fonts

Customize the paths if you serve them from a different location:

tsx
<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

  1. Edit the SVG file(s) in packages/react/src/icons/acro6/
  2. Run the conversion script: node packages/react/scripts/convert-acro6-icons.mjs
  3. 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 /n1 layer): Replaces the /n1 content stream with the icon + updates /n4 status text
  • Acro6 mode (has /FRM + /n0): Blanks the original /n0 (question-mark placeholder), injects the status icon into the FRM stream
ts
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

CategoryShortcutAction
NavigationPageUp / P / KPrevious page
PageDown / N / JNext page
HomeFirst page
EndLast page
ZoomCtrl+=Zoom in
Ctrl+-Zoom out
Ctrl+0Fit page
Ctrl+1Actual size (100%)
Ctrl+2Fit width
ToolsHToggle hand tool
SToggle text select
ViewRRotate clockwise
Shift+RRotate counter-clockwise
F5Toggle fullscreen
SearchCtrl+FToggle find bar
F3Find next
ActionsCtrl+SDownload PDF
Ctrl+PPrint
Ctrl+OOpen 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:

ts
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
        },
      })
    },
  }
}