Skip to content
ComPDF
New Release

Open-Source PDF SDK & AI Document Processing

Get the full self-hosted SDK and AI document processing on GitHub. One-click deploy to quickly build your document workflows.

State Management

UI state is managed by Pinia, split across two stores. This guide describes the store architecture, the key state each holds, and how the apis/ layer interacts with them.

Store setup

packages/webview/src/stores/index.js creates a single Pinia instance and exports setupStore(app) to install it. The stores follow a strict two-store separation (documented in stores/AGENTS.md):

  • Viewer store"how to look at the document" (UI / view state).
  • Document store"what's in the document & how to draw on it" (data + tool styles).

Both stores are referenced by ~102 files across components/ and apis/.

Viewer store — modules/viewer.js (useViewerStore, ~1770 lines)

Holds UI / view state. Highlights:

CategoryFields
View / navigationcurrentPage, scale, oldScale, newScale, zoomLevel (preset array), scrollMode, pageMode, pageLabels.
Theme / displaytheme ('light'/'dark'), fullScreen, language, languages[].
Tool modetoolMode ('view' default), activeHand, activeStickNote, activeActiveMeasure.
Elements open/closeactiveElements{} (boolean map keyed by DataElements.*), activeElementsTab{}, panelSpace{left,right}, openedPanelsNum{left,right}.
Disabled elementsdisabledElements{}{ disabled, style } per element.
Toolbar definitionheaders{} (per group), rightHeaders[], toolItems{}, documentEditorHeaders, toolbarGroup, activeHeaderGroup.
Signature configsignatureDialogTabs, signatureDialogProperties{}, enableSignatureTemplates, digitalSignature{}, selectedSignatureField, disableSignatureTool, electronicSignaturesList[], digitalSignaturesList[].
StampscustomStamps[], stampPanelTabs[], importStamps[].
ComparecompareStatus, compareMode, showCompareTip.
PopupstextPopup[], cropPagePopup[], contentEditorPopup[], annotationPopup[], showAnnotationPopup, popoverChanged.
Form boardformBoardFold, formBoardPosition{}, enableFillForm, skipNoRequired, consecutiveType.
Misc flagslicense, verified, readOnly, userAdmin, isDisabledHeader, downloading, upload, uploadLoading, customLoading, documentEditorSaveStatus, documentEditorSaveAsStatus, webviewerMode.
FontscustomFonts[], fontSizes[].
Panels configgenericPanels[], customModals[].
Annotation flagsannotation{isAnnotationExport, isAnnotationImport}.

Key actions

  • openElement(dataElement, capability?) — sets activeElements[de]=true; closes sibling panels on the same side; on LEFT_PANEL toggles core.toggleSidebar(); on SEARCH_PANEL also opens LEFT_PANEL and switches its tab.
  • closeElement / openElements / closeElements / toggleElement / resetPanels — variants. Closing LEFT_PANEL also calls core.webViewerPageMode('none') and closes SEARCH_PANEL.
  • setActiveElementTab(dataElement, tab) — maps ThumbnailsButtoncore.webViewerPageMode('thumbs'), OutlinesButton'outline'.
  • setActiveToolMode(mode) — guards readOnly and mobile (blocks separation/measurement); closes context panels; calls core.setToolMode(mode).
  • setToolbarGroup(value) — mobile guard for Separation/Measurement.
  • disableElement / enableElement / disableElements / enableElements(de, key?) — toggle disabled flags.
  • Stamp/signature list mutators persist to localStorage.
  • dispatch(action) / getState(key)explicitly the API-access channel; expose store actions/state to apis/.

Document store — modules/document.js (useDocumentStore, ~600 lines)

Holds document data + tool configuration. Highlights:

CategoryFields
Document metatotalPages, loadingProgress, annotationsCount, info, currentPdfData{}, fileHasPwd, pwd.
Annotationsannotations (shallowReactive), selected{}, selectedAnnotation, outlines[], activeOutlineId, searchResults[], activeSearchResult, layers[], selectedLayer.
Current toolactiveTool, markupTool (default HIGHLIGHT), shapeTool (default SQUARE).
Tool style presetsper-tool { color, opacity?, stroke? } (highlight, underline, squiggly, strikeout, square, arc, polygon, polyline, circle, arrow, line, ink, freetext, text, form fields, redaction, remove).
Property panelpropertyPanel{} — form-field/editor property model.
ComparecompareFiles{}, compareSettings{}, compareResult.
Signaturessignatures[], selectedSignature, trustedCertificateLists[], pkcs12, author, annotator, highlightLink, highlightForm, autoJumpNextSign, disableDigitalSignature, disableElectronicSignature.
Measuremeasure{scale, precision}.
Document editordocumentEditor{operationList[], pageList[], selectedPageList[]}.
Undo/redocanUndo{content, annotation}, canRedo{content, annotation}.

Key actions

  • setActiveToolColor(color) — writes this[activeTool].color and calls core.setTool(activeTool).
  • setToolState(tool) — toggles off if same; otherwise looks up map[tool], calls core.setTool(mapTool.tool, mapTool.toolName), sets activeTool, and for form tools calls core.setInitProperty().
  • setActiveToolColor / setPropertyPanel / setCurrentUser / setHighlightLink / setHighlightForm / setAutoJumpNextSignpush the value into core in addition to storing it.
  • initAnnotations / setAnnotations(annotation, type) — manage the annotation array by page index.
  • dispatch(action) / getState(key) — API access.

How apis/ interacts with the stores

Each apis/*.js module is a factory (stores...) => (...args) => result. Two access patterns:

  • Via getters for reads: getActiveTool.jsstore.getActiveTool.
  • Via dispatch for actions: closeElement.jsstore.dispatch('closeElement')(dataElement).

Some APIs (openElement, closeElements, enableElements, disableElements, addPanel, getPanels, isElementOpen, getPassword) use dispatch/getState; others call getters directly. api_helpers/createEncapsulatedStore.js builds the encapsulated viewerStore / documentStore wrappers (exposing only dispatch/getState) used by the popup APIs, getPassword, and getPanels.

Persistence

  • localStorage['language'] — selected language.
  • localStorage['customStamps'], ['electronicSignatures'], ['digitalSignatures'] — stamp/signature lists.