API reference
Every prop, every export, the keyboard map, and the mistakes that cost real hours.
Props
None are required. <PdfBuilder /> on its own is a working editor.
Document
defaultDocument | Uncontrolled starting document. The usual choice. |
document | Controlled document. You own the state. |
onChange(doc) | Every edit. |
onReady(handle) | Once, after mount. The moment to load a saved document. |
onSave(doc) | The toolbar Save button. Return a promise for progress. |
onPreview(doc) | Preview was opened. |
readOnly | Viewer rather than editor. |
className | Extra class on the root element. |
Blocks & actions
registry | A BlockRegistry. Build it once, outside render. |
actions | BlockAction[] — extra buttons on the block action bar. |
Images
onUploadImage(file, ctx) | Store it; return { path, width?, height? }. |
resolveImageUrl(path) | Path to displayable URL. Called on every render. |
onDeleteImage(path) | Optional cleanup. |
imageStoragePath | A hint passed back to you in the upload context. |
imageLibrary | { enabled, onBrowse } — pick from previous uploads. |
Templates
builtinTemplates | Set false to ship only your own. |
templates | DocumentTemplate[]. |
onLoadTemplatesonSaveTemplateonDeleteTemplate | Declared, but nothing calls them. No save-as-template UI exists. See Designs & templates for what to do instead. |
Language, money & data
locale | Which locale pack is active. |
locales | Which locales the user may choose. |
localePacks | LocalePack[] — your translations. |
labels | Override individual label keys. |
messages | Override message strings. |
currencies | ISO codes and/or CurrencyDefinition objects, in one array. |
formatCurrency(value, ctx) | Escape hatch. Return undefined to fall back. |
fonts | The typefaces offered in font pickers. |
variables | VariableDefinition[] — bind real records to tokens. |
sampleData | Sample values for databound previews. |
Interface
ui | { hide, show, disable, slots, components }. |
fields | { '{blockType}.{tab}.{fieldKey}': { hidden, disabled, label } }. |
theme / themes | Chrome tokens, and document token defaults for new documents. |
layout / onLayoutChange | Panel arrangement. |
persistKey | The only way anything reaches browser storage. |
setup, initialConfig, onSetupComplete, setupCompleted | The first-run wizard. |
AI, licensing, export, errors
onAiDesign(request) | Its presence is the AI feature switch. |
onGenerate(input, ctx) | Smaller, field-level AI assistance. |
aiRequiresFeature | Licence feature the AI button requires. |
license | { plan?, features? }. Presentation only. |
onLicenseRequired(feature, blockType?) | Show your upgrade path. |
onRenderPdf(doc) | Replace the built-in PDF path. Return a Blob or URL. |
onError(report) | A block crashed. Report it; the app stays up. |
devMode | Developer affordances. Defaults to non-production. |
The ref handle
interface PdfBuilderHandle {
getDocument(): PdfDocument
loadDocument(document: PdfDocument | unknown): void // migrated, validated, one undo step
undo(): void
redo(): void
}
Exports
Everything exported from the package entry point is supported. Anything not exported is internal and may change without notice.
| Group | Exports |
|---|---|
| Component | PdfBuilder, ErrorBoundary, PACKAGE_VERSION |
| Document | createDocument, migrate, migrations, validate, resolveStyle |
| Operations | createBlockInstance, appendBlockRow, insertBlockRowAfter, findBlock, updateBlockContent, updateBlockOverrides, setBlockLayout, clearBlockOverrides, removeBlock, duplicateBlock |
| Blocks | createBuiltinRegistry, builtinBlocks, BlockRegistry, createDefaultRegistry |
| Templates | createBuiltinTemplates |
| Tokens & data | PLACEHOLDER, PLACEHOLDER_SAMPLES, token, interpolateText, interpolateContent |
| Theme | defaultTokens, defaultPageSettings, spacing, builtinThemes, lightTheme, darkTheme, getBuiltinTheme |
| Money | formatCurrency, currencyContextFromTokens, currencyLabel, parseAmount |
| i18n | LABEL_KEYS, en, createLabelResolver, useLabel |
| AI | buildDesignSchema, normalizeAiResult |
| Store | createBuilderStore |
| Layout | resolveLayout, defaultLayout, gridTemplateColumns |
Types
| Group | Types |
|---|---|
| Document | PdfDocument, Block, Row, Column, Region, CoverPage, PageSettings, DesignTokens, Spacing, BlockPageBehavior, CURRENT_DOCUMENT_VERSION |
| Blocks | BlockDefinition, BlockLayout, BlockCategory, DesignCategory, BlockRenderProps, RenderContext, EditorProps, FieldSchema, FieldBase, SelectOption, BlockTab |
| Props | PdfBuilderProps, PdfBuilderHandle, BlockAction, UploadContext, UploadedImage, LibraryImage, FieldControl |
| Config | Theme, LocalePack, DocumentTemplate, TemplateCategory, TemplateMeta, VariableDefinition, UiElement, SlotName, SlotComponents, LayoutConfig, BuilderConfig, SetupStep |
| Money | CurrencyDefinition, CurrencyFormatContext, CurrencyDisplay |
| AI | AiDesignRequest, AiDesignResult, AiDesignSchema, DesignSchemaInput, NormalizeOptions, AiInput, AiContext, AiResult |
| Schema helpers | CreateDocumentOptions, MigrationStep, StyleLayers |
| Errors & i18n | BuilderErrorReport, LabelKey, LabelResolver |
| Store advanced | BuilderState, BuilderStore, DocumentSlice, SelectionSlice, UiSlice, HistorySlice |
The store types are exported, but reaching into the store is not the supported path.
createBuilderStore and its slices exist so you can build something unusual — a
second view onto the same document, say. For everything ordinary, use the props and the ref
handle. Store internals move between releases; props do not.
Keyboard
| Ctrl/Cmd + Z | Undo |
| Ctrl/Cmd + Shift + Z | Redo |
| Ctrl/Cmd + S | Save |
| Delete / Backspace | Delete the selected block |
| Ctrl/Cmd + D | Duplicate |
| Esc | Deselect, or close a dialog |
| Ctrl/Cmd + Y | Redo, the Windows spelling |
That is the complete list.
There is no arrow-key nudge, no copy/paste, no select-all and no block-to-block Tab
traversal. Selection is single-block only — no shift-click, no marquee.
Shortcuts are not disabled by
readOnly.
A user can still select a block and press Delete or
Ctrl+D in a read-only builder and change the document. Drag-and-drop
is genuinely absent in read-only. If read-only has to hold, enforce it where you
save, not here.
Error handling
A block that throws is contained. It does not unmount your application.
<PdfBuilder
onError={(report) => {
// { message, blockId?, blockType?, stack? }
Sentry.captureException(new Error(report.message), { extra: report })
}}
/>
The report goes to you, never to a network.
The package has no reporting endpoint of its own, and never will.
Multiple builders on one page
Supported, and genuinely isolated. Each instance has its own store, selection, history, dialogs, registry, locale, currency, AI state and persistence. Two builders can run different currencies with different custom formatters and never leak into each other.
<PdfBuilder defaultDocument={invoice} persistKey="invoice" />
<PdfBuilder defaultDocument={quote} persistKey="quote" />
Troubleshooting
| Symptom | Cause |
|---|---|
| Unstyled markup | styles.css not imported, or its build output not linked. With Encore, CSS imported from JS attaches to the JS entry — link that entry too. |
| Builder one pixel tall | The container has no height. |
| "Invalid hook call" | Two copies of React. |
| Empty div, no error (Symfony UX React) | The React components were never registered — the recipe only patches assets/bootstrap.js by that exact filename. |
| A raw label key on screen | That key has no label anywhere. Usually a typo or a custom block's labelKey. |
| Images broken | resolveImageUrl missing, or returning a URL that 404s. |
| A design "does nothing" | A manual override on that block outranks it. Reset the block's style. |
| Currency shows as a bare code | The runtime does not know that code. Register a CurrencyDefinition, or supply formatCurrency. |
| Wrong number grouping | The locale is POSIX (en_IN) rather than BCP 47 (en-IN). We convert it for createDocument; the rest of your stack will not. |
| Palette flickers or resets | A new registry object on every render. Build it once. |
| Package changes not appearing | Installing from a local tarball: Yarn 1 caches by name+version and keeps the first one it saw. |
| SSR crash | Render client-side only. The builder measures real elements. |
Things that will never happen
Guarantees, not current behaviour. You can design around these.
The package will never make a network request.
No fetch, no axios, no SDK client, no WebSocket, no hardcoded URL — including for telemetry,
licensing or error reporting. Everything crosses the boundary through a callback you wrote.
It will never write to browser storage unless you pass
persistKey.
It will never create a global.
No
window.Storvexa, no shared mutable registry, no querying DOM outside its own root.
It will never store a URL or base64 image in the document.
Opaque paths, always.
It will never destroy content to change presentation.
Applying a design, switching a layout or changing tokens cannot delete a word the user typed.
It will never silently drop a saved document.
Every load migrates and validates. If something genuinely cannot be represented, you are told.