API reference

Every prop, every export, the keyboard map, and the mistakes that cost real hours.

@storvexa/pdf-builder Chapter 14 of 14
Documentation

Props

None are required. <PdfBuilder /> on its own is a working editor.

Document

defaultDocumentUncontrolled starting document. The usual choice.
documentControlled 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.
readOnlyViewer rather than editor.
classNameExtra class on the root element.

Blocks & actions

registryA BlockRegistry. Build it once, outside render.
actionsBlockAction[] — 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.
imageStoragePathA hint passed back to you in the upload context.
imageLibrary{ enabled, onBrowse } — pick from previous uploads.

Templates

builtinTemplatesSet false to ship only your own.
templatesDocumentTemplate[].
onLoadTemplates
onSaveTemplate
onDeleteTemplate
Declared, but nothing calls them. No save-as-template UI exists. See Designs & templates for what to do instead.

Language, money & data

localeWhich locale pack is active.
localesWhich locales the user may choose.
localePacksLocalePack[] — your translations.
labelsOverride individual label keys.
messagesOverride message strings.
currenciesISO codes and/or CurrencyDefinition objects, in one array.
formatCurrency(value, ctx)Escape hatch. Return undefined to fall back.
fontsThe typefaces offered in font pickers.
variablesVariableDefinition[] — bind real records to tokens.
sampleDataSample values for databound previews.

Interface

ui{ hide, show, disable, slots, components }.
fields{ '{blockType}.{tab}.{fieldKey}': { hidden, disabled, label } }.
theme / themesChrome tokens, and document token defaults for new documents.
layout / onLayoutChangePanel arrangement.
persistKeyThe only way anything reaches browser storage.
setup, initialConfig, onSetupComplete, setupCompletedThe first-run wizard.

AI, licensing, export, errors

onAiDesign(request)Its presence is the AI feature switch.
onGenerate(input, ctx)Smaller, field-level AI assistance.
aiRequiresFeatureLicence 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.
devModeDeveloper 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.

GroupExports
ComponentPdfBuilder, ErrorBoundary, PACKAGE_VERSION
DocumentcreateDocument, migrate, migrations, validate, resolveStyle
OperationscreateBlockInstance, appendBlockRow, insertBlockRowAfter, findBlock, updateBlockContent, updateBlockOverrides, setBlockLayout, clearBlockOverrides, removeBlock, duplicateBlock
BlockscreateBuiltinRegistry, builtinBlocks, BlockRegistry, createDefaultRegistry
TemplatescreateBuiltinTemplates
Tokens & dataPLACEHOLDER, PLACEHOLDER_SAMPLES, token, interpolateText, interpolateContent
ThemedefaultTokens, defaultPageSettings, spacing, builtinThemes, lightTheme, darkTheme, getBuiltinTheme
MoneyformatCurrency, currencyContextFromTokens, currencyLabel, parseAmount
i18nLABEL_KEYS, en, createLabelResolver, useLabel
AIbuildDesignSchema, normalizeAiResult
StorecreateBuilderStore
LayoutresolveLayout, defaultLayout, gridTemplateColumns

Types

GroupTypes
DocumentPdfDocument, Block, Row, Column, Region, CoverPage, PageSettings, DesignTokens, Spacing, BlockPageBehavior, CURRENT_DOCUMENT_VERSION
BlocksBlockDefinition, BlockLayout, BlockCategory, DesignCategory, BlockRenderProps, RenderContext, EditorProps, FieldSchema, FieldBase, SelectOption, BlockTab
PropsPdfBuilderProps, PdfBuilderHandle, BlockAction, UploadContext, UploadedImage, LibraryImage, FieldControl
ConfigTheme, LocalePack, DocumentTemplate, TemplateCategory, TemplateMeta, VariableDefinition, UiElement, SlotName, SlotComponents, LayoutConfig, BuilderConfig, SetupStep
MoneyCurrencyDefinition, CurrencyFormatContext, CurrencyDisplay
AIAiDesignRequest, AiDesignResult, AiDesignSchema, DesignSchemaInput, NormalizeOptions, AiInput, AiContext, AiResult
Schema helpersCreateDocumentOptions, MigrationStep, StyleLayers
Errors & i18nBuilderErrorReport, LabelKey, LabelResolver
Store advancedBuilderState, 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 + ZUndo
Ctrl/Cmd + Shift + ZRedo
Ctrl/Cmd + SSave
Delete / BackspaceDelete the selected block
Ctrl/Cmd + DDuplicate
EscDeselect, or close a dialog
Ctrl/Cmd + YRedo, 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

SymptomCause
Unstyled markupstyles.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 tallThe 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 screenThat key has no label anywhere. Usually a typo or a custom block's labelKey.
Images brokenresolveImageUrl 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 codeThe runtime does not know that code. Register a CurrencyDefinition, or supply formatCurrency.
Wrong number groupingThe 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 resetsA new registry object on every render. Build it once.
Package changes not appearingInstalling from a local tarball: Yarn 1 caches by name+version and keeps the first one it saw.
SSR crashRender 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.