PDF Generation Template Editor
Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.
Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.
The UI is a Vue 3 component tree rooted at App/index.vue. This guide maps the component directory structure and the key areas, so you know where to look when forking or extending the UI.
main.js → createApp(App = components/Suspenser.vue)
→ setupStore(app) + i18n(app)
→ mount('#app')
Suspenser.vue → <Suspense> fallback="loading…" → <App/>
App/index.vue → the actual viewer rootSuspenser.vue wraps App/index.vue in <Suspense> because App uses top-level await (i18nextPromise, loadConfig).
App/index.vue Renders the chrome and wires the engine:
#outerContainer.<Header /> (hidden when header is disabled), then a .content row with the document area + side panels + overlays.<DocumentContainer />, <CompareDocumentContainer />, and conditionally <DocumentEditorContainer /> (only in document tool mode).useViewer.getGenericPanels via v-for, wrapped in the generic <Panel> shell. Inner components resolve via NoLazyComponents (eager), LazyLoadComponents (lazy), or <CustomElement> (user render).<SignCreatePanel>, <SignCreateDialog>, <CustomStamp>.initDocument, defineWebViewerInstanceUIAPIs, loads hash params (css, theme, header), and posts viewerLoaded to window.parent. Defines window.instance.changeFile.| Directory | Purpose |
|---|---|
App/ | Root application component. |
Header/ | The top bar (Header.vue). |
HeaderItems/ | Generic toolbar renderer (HeaderItems.vue) + HeaderItemsListener.js sync hub. |
Ribbons/ | Toolbar-group switcher. |
ToolsHeader/ | Secondary contextual toolbar row. |
FormBoard/ | Form-field creation palette. |
DocumentContainer/ | PDF render surface + document-scoped overlays (largest component, ~31k). |
CompareDocumentContainer/ | Compare-mode viewer (registers instances 2 & 3). |
DocumentEditorContainer/ | Page editor (insert/delete/rotate/extract/merge/move/crop). |
LeftPanel/ | Tabbed left sidebar (thumbnails, outlines, annotations, layers, signatures, search). |
RightPanel/ | Form-field properties (General/Appearance/Preferences). |
Panel/ | Generic slide-in panel shell. |
StylePanel/ | Annotation & measurement properties. |
StampPanel/ | Stamp picker. |
LinkPanel/, ContentEditorPanel/, RedactionPanel/, ColorSeparationPanel/, RightPanelPageMode/ | Other built-in panels. |
Popups/ | AnnotationPopup, TextPopup, FreetextPopup, CropPagePopup, ContentEditorPopup. |
Dialogs/ | Modal dialogs (page ops, signature, compare, measurement, stamp, redaction, settings). |
Signatures/ | SignCreatePanel, SignCreateDialog, DigitalSignCreatePanel, DigitalKeyboardCreatePanel. |
SignatureContainer/ | Left-panel signature tab. |
Icon/ | ~270 SVG-as-Vue icon components, referenced by name string. |
Button/, CustomButton/, Dropdown/, CustomElement/ | Primitives used by HeaderItems and Popups. |
Message/ | Global toast (window.$message). |
AnnotationContainer/, Outlines/, LayerContainer/, SearchContainer/ | Left-panel tab contents. |
MeasurementBoard/, MeasureCurveGuide/, MeasurePanel/ | Measurement tools. |
Password/ | Password entry/set dialogs. |
SecurityToolbar/, SignatureToolBar/, ComparedToolbar/, FillForm/ | Mode-specific toolbars. |
LazyLoadWrapper/ | Async-component + Suspense wrapper and the panel registry. |
CustomModal/, ModalContainer/ | UI.addCustomModal plumbing. |
PageNavOverlay/, ZoomOverlay/ | Floating overlays. |
Header.vue renders <HeaderItems :items="useViewer.getActiveHeaderItems" /> (the array for activeHeaderGroup). HeaderItems.vue dispatches on item.type (toolButton, toggleElementButton, actionButton, statefulButton, customElement, spacer, divider), computes visibleItems (mobile/PC + isElementDisabled), and applies responsive hide classes. HeaderItemsListener.js keeps toolbar buttons in sync with selection/tool state.
The .document-container sizes against panelSpace and topSpace. The inner .document div is the PDF render surface, wired with click/touch/mousedown/dblclick/contextmenu handlers that dispatch onto core.eventBus(). initViewer() calls core.initializeViewer({ container, viewer, thumbnailView, outlineView, findbarView, toggleButton }) and registers engine event listeners. It also hosts all five Popups and most document-scoped dialogs.
Five floating, position-computed popovers (via helpers/getPopupPosition), driven by useViewer.getPopupItems(<key>) and filtered by isElementDisabled. See Popups.
components/Icon/ contains ~270 single-purpose SVG-as-Vue-render-function icon components, referenced by name strings (e.g. icon: 'Pantool') in header-item descriptors and popup items, not imported directly at call sites.
UI.setHeaderItems(cb) mutates headers in the store; HeaderItems.vue re-renders.UI.addPanel appends to genericPanels; the root App renders them through Panel.vue + <CustomElement>.UI.annotationPopup / textPopup / contentEditorPopup / cropPagePopup mutate popup item arrays.UI.addCustomModal appends to customModals; CustomModal + ModalContainer render them.openElement / closeElement / disableElements drive visibility through the store's activeElements / disabledElements maps.