VerifyKitv0.5.1

Vanilla JS

@trexolab/verifykit-vanilla is a zero-build, drop-in PDF viewer with signature verification. No React knowledge required -- load from a CDN or install via npm and embed a full-featured PDF viewer in any web page.

The package bundles React internally and wraps @trexolab/verifykit-react to expose all viewer features as imperative JavaScript methods.

CDN Installation

Add the stylesheet and script tags to your HTML:

html
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://verifykit.trexolab.com/cdn/verifykit.css">
  <style>
    html, body { height: 100%; margin: 0; padding: 0; }
  </style>
</head>
<body>
  <div id="viewer" style="width: 100%; height: 100vh;"></div>
 
  <script src="https://verifykit.trexolab.com/cdn/verifykit.umd.js"></script>
  <script>
    const viewer = VerifyKit.create(document.getElementById('viewer'), {
      workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
      theme: { mode: 'system' },
      features: {
        signatures: true,
        print: true,
        download: true,
        search: true,
        fullscreen: true,
      },
    })
 
    fetch('/document.pdf')
      .then(r => r.arrayBuffer())
      .then(buf => viewer.load(buf, 'document.pdf'))
  </script>
</body>
</html>

The UMD bundle includes the WASM core. The .wasm binary file must be served from the same directory as the JS file. When using the CDN, this is handled automatically.

npm Installation

For bundler-based projects:

bash
npm install @trexolab/verifykit-vanilla
ts
import { create } from '@trexolab/verifykit-vanilla'
import '@trexolab/verifykit-vanilla/verifykit.css'
 
const viewer = create(document.getElementById('viewer'), {
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  theme: { mode: 'system' },
  features: {
    signatures: true,
    print: true,
    download: true,
  },
})
 
const result = await viewer.load(pdfArrayBuffer, 'report.pdf')
console.log('Signatures:', result.signatures.length)
 
viewer.destroy()

Creating a Viewer

Use VerifyKit.create(container, options?) to mount a viewer on a DOM element:

ts
const viewer = VerifyKit.create(document.getElementById('viewer'), {
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  theme: { mode: 'system' },
})

Container requirements: The container element must exist in the DOM and have explicit dimensions (width and height). The viewer fills its parent -- if the parent has zero height, nothing renders. A common pattern is style="width: 100%; height: 100vh;".

If the container is null or undefined, create() throws "requires a valid HTMLElement". Make sure the element exists before calling create(), or wrap the call in a DOMContentLoaded listener.

Loading Documents

Use viewer.load(source, fileName?) to load a PDF. It accepts three input types:

ts
// URL string
await viewer.load('/documents/report.pdf', 'report.pdf')
 
// File object (e.g., from a file input)
const file = inputElement.files[0]
const buffer = await file.arrayBuffer()
await viewer.load(buffer, file.name)
 
// ArrayBuffer
const response = await fetch('/document.pdf')
const buf = await response.arrayBuffer()
await viewer.load(buf, 'document.pdf')

load() returns a Promise<VerificationResult> containing all signature data. You can inspect the result immediately:

ts
const result = await viewer.load(buffer, 'doc.pdf')
for (const sig of result.signatures) {
  console.log(sig.name, sig.overallStatus)
}

All imperative methods (like goToPage, zoomIn) are no-ops until load() has resolved. Always await the load before calling other methods.

Configuration Options

ts
interface VerifyKitOptions {
  // Worker (REQUIRED)
  workerUrl: string             // URL to the PDF.js worker script (required)
 
  // Theme
  theme?: {
    mode?: 'light' | 'dark' | 'system'
    overrides?: Record<string, string>
  }
 
  // Features
  features?: VerifyKitFeatures
 
  // Core config
  trustStore?: TrustStoreConfig
  plugins?: VerifyKitPlugin[]
 
  // i18n
  locale?: string
  translations?: Partial<TranslationStrings>
 
  // Callbacks
  onVerified?: (result: VerificationResult) => void
  onError?: (error: LoadError) => void
  onDocumentLoaded?: (info: { pageCount: number; fileName: string }) => void
  onPageChange?: (page: number) => void
  onZoomChange?: (scale: number) => void
  onThemeChange?: (mode: 'light' | 'dark') => void
}

Instance Methods

Once a document is loaded, the viewer instance exposes a full programmatic API.

ts
viewer.goToPage(5)          // Jump to page 5
viewer.goToNextPage()       // Next page
viewer.goToPreviousPage()   // Previous page
viewer.goToFirstPage()      // First page
viewer.goToLastPage()       // Last page
viewer.getCurrentPage()     // Returns current page number
viewer.getPageCount()       // Returns total page count

Zoom

ts
viewer.zoomIn()             // Zoom in one step
viewer.zoomOut()            // Zoom out one step
viewer.zoomTo(2.0)          // Set zoom to 200%
viewer.setFitMode('width')  // Fit to width ('none', 'width', 'page')
viewer.getZoom()            // Returns current zoom scale

Rotation

ts
viewer.rotateCW()           // Rotate 90 degrees clockwise
viewer.rotateCCW()          // Rotate 90 degrees counter-clockwise
viewer.getRotation()        // Returns current rotation in degrees
ts
viewer.openSearch()         // Open the search bar
viewer.closeSearch()        // Close the search bar
ts
viewer.print()              // Open print dialog
viewer.download()           // Download the PDF

Fullscreen

ts
viewer.enterFullscreen()    // Enter fullscreen mode
viewer.exitFullscreen()     // Exit fullscreen mode
viewer.toggleFullscreen()   // Toggle fullscreen

Signature Panel

ts
viewer.openSignaturePanel() // Open the signature details panel
viewer.closeSignaturePanel()// Close the signature panel

Theme

ts
viewer.setTheme('dark')     // Set theme ('light', 'dark', 'system')

Revalidation

ts
viewer.revalidate()             // Re-verify all signatures on the current buffer

State Inspection

ts
viewer.getVerificationResult()  // Returns VerificationResult or null
viewer.getSignatures()          // Returns PdfSignature[]

Event Handling

Subscribe to viewer events using viewer.on(event, callback). Each call returns an unsubscribe function.

ts
// Verification complete
viewer.on('verified', (result) => {
  console.log('Signatures:', result.signatures.length)
})
 
// Document loaded
viewer.on('documentLoaded', (info) => {
  console.log(`Loaded ${info.pageCount} pages: ${info.fileName}`)
})
 
// Page navigation
const unsub = viewer.on('pageChange', (page) => {
  console.log('Current page:', page)
})
 
// Zoom changes
viewer.on('zoomChange', (scale) => {
  console.log('Zoom:', Math.round(scale * 100) + '%')
})
 
// Theme changes
viewer.on('themeChange', (mode) => {
  console.log('Theme:', mode)
})
 
// Rotation
viewer.on('rotationChange', (rotation) => {
  console.log('Rotation:', rotation)
})
 
// Fullscreen
viewer.on('fullscreenChange', (isFullscreen) => {
  console.log('Fullscreen:', isFullscreen)
})
 
// Error (receives a LoadError object with name and message)
viewer.on('error', (error) => {
  console.error('Viewer error:', error.name, error.message)
})
 
// Unsubscribe
unsub()

Feature Flags

Toggle individual viewer features via the features option. Each feature defaults to the value shown:

ts
interface VerifyKitFeatures {
  search?: boolean       // default: true
  print?: boolean        // default: true
  download?: boolean     // default: false
  signatures?: boolean   // default: true
  thumbnails?: boolean   // default: true
  fullscreen?: boolean   // default: true
  themeToggle?: boolean  // default: true
  openFile?: boolean     // default: false
  rotation?: boolean     // default: true
  contextMenu?: boolean  // default: true
  properties?: boolean   // default: true
  shortcuts?: boolean    // default: true
  highlights?: boolean   // default: true
}

Example -- enable download and file opening, disable print:

ts
const viewer = VerifyKit.create(el, {
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  features: {
    download: true,
    openFile: true,
    print: false,
  },
})

Internally, features flags are mapped to defaultLayoutPlugin({ disable: {...} }).

With File Input

A common pattern using a standard HTML file input:

html
<input type="file" id="file-input" accept=".pdf" />
<div id="viewer" style="width: 100%; height: 80vh;"></div>
 
<script src="https://verifykit.trexolab.com/cdn/verifykit.umd.js"></script>
<script>
  const viewer = VerifyKit.create(document.getElementById('viewer'), {
    workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  })
 
  document.getElementById('file-input').addEventListener('change', (e) => {
    const file = e.target.files[0]
    if (!file) return
    file.arrayBuffer().then(buf => viewer.load(buf, file.name))
  })
</script>

With Core Plugins

Core verification plugins (like revocation checking) can be passed through to the WASM engine:

ts
import { create } from '@trexolab/verifykit-vanilla'
import { revocationPlugin } from '@trexolab/verifykit-plugin-revocation'
 
const viewer = create(document.getElementById('viewer'), {
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  plugins: [revocationPlugin()],
  trustStore: {
    certificates: [myRootCaPem],
    mode: 'merge',
  },
})
 
const result = await viewer.load(pdfBuffer, 'document.pdf')
// Revocation checks now include live CRL/OCSP lookups

Self-Hosting

When self-hosting instead of using a CDN, copy the entire dist/ directory:

bash
cp -r node_modules/@trexolab/verifykit-vanilla/dist/ public/verifykit/

Then reference the files from your HTML:

html
<link rel="stylesheet" href="/verifykit/verifykit.css">
<script src="/verifykit/verifykit.umd.js"></script>

The WASM binary is resolved relative to the JS file's URL. As long as both files are served from the same directory, loading is automatic.

Cleanup

Always call destroy() when the viewer is no longer needed. This cleans up store subscriptions, event listeners, and worker blob URLs:

ts
viewer.destroy()

In single-page applications, call destroy() when the viewer's container is removed from the DOM (e.g., on route change or component unmount).