Events
Subscribe to what the person is doing and to lifecycle changes. Global events come from
Kernstra.events; per-viewer events from viewer.on(). Subscribing to the wrong one is silent.Global · Kernstra.events
initializedevent
payload: { version: string }
Kernstra.init() completed.TypeScript
Kernstra.events.on('initialized', ({ version }) => console.log(version));
licenseChangedevent
payload: LicenseState
The license was evaluated, replaced, paused or revoked. A valid license fills
env, plan, features, offline and, when it has one, expiresAt; an invalid one fills reason (and pauseReason when paused) — see LicenseState. A verdict that takes rights away is reported at once but reaches only the next load; documents already open keep the rights they were opened with.TypeScript
Kernstra.events.on('licenseChanged', (state) => setWatermarked(state.watermark));
documentLoadedevent
payload: { document: PDFDocument; pageCount: number; hasPassword: boolean }
A document was opened by
fromUrl, fromFile, fromBytes or fromUrlProgressive (progressive: as soon as it can be shown); document is the one, so a host with several knows which. Not fired when the viewer reloads the document after an edit or an undo.TypeScript
Kernstra.events.on('documentLoaded', ({ pageCount }) => setPageCount(pageCount));
documentClosedevent
payload: { document: PDFDocument }
A document was closed:
document is the one, closed by then — compare it, never call it.TypeScript
Kernstra.events.on('documentClosed', ({ document }) => { if (document === doc) setPageCount(0); });
Per viewer · viewer.on()
pageChangedevent
payload: { pageIndex: number }
Current page changed — by scrolling, navigation, a link, or a reload that left fewer pages than the one shown. Not by a zoom.
TypeScript
viewer.on('pageChanged', ({ pageIndex }) => setCurrentPage(pageIndex));
zoomChangedevent
payload: { scale: number }
Zoom level changed, by any means (1.0 = 100%).
TypeScript
viewer.on('zoomChanged', ({ scale }) => setZoom(Math.round(scale * 100)));
toolChangedevent
payload: { tool: ToolName | null; previous: ToolName | null }
The active tool changed —
tool runs now (between tools the resting tool, 'selectText' by default), previous was reported before it; null only with defaultTool: null. Fires once the tool has started.TypeScript
viewer.on('toolChanged', ({ tool }) => setActiveTool(tool));
panelChangedevent
payload: { panel: SidebarTab | null; previous: SidebarTab | null }
The open sidebar panel changed —
panel shows now (null: the sidebar is collapsed), previous was reported before it. Every change, whoever made it: openPanel(), the rail, a toolbar toggle, the drawer's backdrop, Escape inside the drawer, a tab the license takes away. The panel the viewer starts with opens while it is built, before a handler can be added: read activePanel for the state at any moment.TypeScript
viewer.on('panelChanged', ({ panel }) => { myPagesButton.ariaPressed = String(panel === 'pages'); });
pagesChangedevent
payload: { pageCount: number }
The pages changed — one added, removed, moved, duplicated, imported or turned, by a tool, Manage Pages, a thumbnail's menu, the document API, undo or redo — once the view shows them, before the
documentChanged of the same change. Re-read anything you hold per page. Found by comparing each page's identity and size with what was shown: a page turned by 180° and turned back by undo keeps both and is reported by documentChanged alone.TypeScript
viewer.on('pagesChanged', ({ pageCount }) => setPageCount(pageCount));
formFieldChangedevent
payload: { field: FormFieldInfo }
A form field's value changed — by the user (per keystroke in a plain text field; on Enter or leaving it in a formatted one), by a calculation, or once per field
doc.forms.setValues() applies. field is a snapshot carrying the field's current value — a check box's or radio group's export value when on, 'Off' when off, what doc.forms.setValues takes. A signature field signed fires it too, the snapshot's signature now 'appearance' and its value '', and then signatureCaptured with the picture.TypeScript
viewer.on('formFieldChanged', ({ field }) => console.log(field.name, field.value));
formFieldFocusedevent
payload: { field: FormFieldInfo }
A form field's editor gained focus.
field is a snapshot as formFieldChanged carries it.TypeScript
viewer.on('formFieldFocused', ({ field }) => showHelpFor(field.name));
formFieldBlurredevent
payload: { field: FormFieldInfo }
A form field's editor lost focus.
field is a snapshot as formFieldChanged carries it.TypeScript
viewer.on('formFieldBlurred', ({ field }) => validate(field));
signatureCapturedevent
payload: { fieldName: string; pageIndex: number; method: 'draw' | 'type' | 'upload' | 'host'; dataUrl: string }
A form's signature field was signed (
'host': by callbacks.onSignatureRequest). The Sign tool placing a signature in the page reports contentPlaced instead.TypeScript
viewer.on('signatureCaptured', ({ fieldName, method }) => track('signed', { fieldName, method }));
textChangedevent
payload: { changes: TextChange[] }
Edit Text wrote its edits into the document — on Done, on leaving the tool any other way, before an undo, or from
viewer.tools.editText.commit(). Once per commit, with every block it wrote; each change is { pageIndex, blockId, kind: 'text' | 'style' | 'box' | 'deleted', oldText, newText } and kind says what changed. oldText is the block's text as the session found it, newText as the commit left it, both with their lines joined by one space; both empty under a license without extract.TypeScript
viewer.on('textChanged', ({ changes }) => audit(changes));
documentChangedevent
payload: { source: DocumentChangeSource; tool?: ToolName; hasUnsavedChanges: boolean; canUndo: boolean; canRedo: boolean }
The document changed — a tool wrote (
source: 'tool', tool names it), a page was turned, moved, added or deleted ('pages'), a bookmark, attachment or comment was edited ('outline', 'attachments', 'comments'), a form field was filled in, signed or set by doc.forms.setValues() ('forms' — every commit of a value, each keystroke), the document API was called ('api'; the Security tool's protect and unprotect included), undo or redo stepped ('undo', 'redo'). Once per change, after it is in the document, with the viewer's state after it. Not for a history step that left the document as it was. The hook for saving as the user works and for undo / redo buttons — see Saving as the user works.TypeScript
viewer.on('documentChanged', ({ canUndo, canRedo }) => setHistoryButtons(canUndo, canRedo));
contentPlacedevent
payload: { tool: ToolName; pageIndex: number }
The user added something with a tool — a highlight, text mark or black-out, note, link, stamp, image, signature (the Sign tool; a form field reports
signatureCaptured), added text, shape, drawing or text box. Once per new thing, a duplicate included, when it is committed; not for a move, resize, edit or undo. Selection-bar highlights report 'textHighlight', its underline, squiggly underline, strikeout and black-out 'selectText'.TypeScript
viewer.on('contentPlaced', ({ tool, pageIndex }) => track('placed', { tool, pageIndex }));
annotationsChangedevent
payload: { pageIndex: number; changes: AnnotationChange[] }
Reported from a reading of the page after the change (adding the listener reads every page once, promptly, as the baseline): a page's annotations changed — one added, deleted, or modified (moved, resized, recolored, restyled, reworded), by a tool, a panel,
doc.annotations, undo or redo; each change is { type: 'added' | 'modified' | 'deleted', id }. Every annotation but pop-ups and form widgets; a reply and a review status are annotations of their own, reported added. id is what doc.annotations.get(id) takes; an undo that brings one back is an added. Not for the annotations a document opens with. Needs the annotations feature.TypeScript
viewer.on('annotationsChanged', ({ pageIndex }) => void refreshMarks(pageIndex));
commentsChangedevent
payload: { pageIndex: number; changes: CommentChange[] }
Reported from a reading of the page after the change (adding the listener reads every page once, promptly, as the baseline): a page's comments changed — one added, edited, deleted, replied to or given a status, by a tool, the Comments panel,
doc.annotations, undo or redo; each change is { type: 'added' | 'edited' | 'deleted' | 'replied' | 'status', id }. Not for the comments a document opens with. After pages are added, removed or moved, each page whose comments differ from what that page number held. Read them with doc.annotations.comments(pageIndex). A viewer's event — a document with no viewer reports none. Under a license with annotations.TypeScript
viewer.on('commentsChanged', async ({ pageIndex }) => syncComments(await doc.annotations.comments(pageIndex)));
errorevent
payload: { code: ErrorCodeValue; message: string; fatal: boolean }
A failure inside the viewer's own work, which no call of yours could catch — see Error handling.
TypeScript
viewer.on('error', ({ code, message, fatal }) => report(code, message, fatal));
payload: { signatures: SavedSignature[] }
The signatures the user keeps for reuse changed — the whole list, to store and pass back as
tools.sign.savedSignatures; see Keeping saved signatures and stamps.TypeScript
viewer.on('savedSignaturesChanged', ({ signatures }) => localStorage.setItem('signatures', JSON.stringify(signatures)));
userStampsChangedevent
payload: { stamps: SavedStamp[] }
The stamps made with "New stamp" changed — the whole list, to store and pass back as
tools.stamp.userStamps.TypeScript
viewer.on('userStampsChanged', ({ stamps }) => localStorage.setItem('stamps', JSON.stringify(stamps)));
exportStartedevent
payload: Record<string, never>
Export began — from the toolbar's Download or an exporter from
viewer.createExporter(); a new PDFExporter(doc) you construct reports to no viewer.TypeScript
viewer.on('exportStarted', () => setBusy(true));
exportCompletedevent
payload: { sizeBytes: number; partial: boolean; pdfA?: 'kept' | 'dropped' }
Export completed — same caveat as
exportStarted. partial is true for a page range; an export of the whole document clears hasUnsavedChanges. pdfA for a PDF/A file: whether the file saved still claims it.TypeScript
viewer.on('exportCompleted', ({ sizeBytes }) => { setBusy(false); log(sizeBytes); });