Skip to content

White labelling ​

Two layers can be white-labelled independently: the documents your users produce and the editor they use.

Documents ​

Give each customer a theme. Store one template; render it with the customer's theme:

ts
await renderPdf({ template: quarterlyReview, data, theme: themesByTenant[tenantId] });

Everything that should vary per customer belongs in the theme: colours, fonts, logo, and meta (company name, regulatory strings, addresses, phone numbers) which templates read as {{ theme.meta.company }}. Nothing tenant-specific needs to live in the template.

The editor ​

features.whiteLabel = true hides the BroadPaper mark in the toolbar. The editor's chrome is themed through CSS custom properties on the .bpe root, so you can restyle it to match your product:

css
.bpe { --bpe-accent: #7c5cff; --bpe-primary: #e0483c; --bpe-font: "Your Sans", system-ui, sans-serif; --bpe-radius: 4px; }

--bpe-accent is what marks things out: a selected block's outline, a focused input's ring, the active tab. --bpe-primary is only the filled call to action, and it defaults to the accent — set it separately when your brand colour is one you would not want drawn around a selection. A red accent, for instance, makes every selected block look like a validation error.

appearance: "dark" | "light" | "system" switches the built-in palettes.

Other feature flags let you shape the experience per plan or per role:

FlagHides / disables
pdfExportExport menu
themesTheme switcher
customBlocksCustom blocks in the palette
libraryReusable content panel
styleOverridesPer-block style overrides (keeps everything on-brand)
pageSettings, documentStyles, headerFooterDocument-level settings
layers, dataPanel, validation, jsonView, expressionsIndividual panels and power features

Locked nodes (locked: true) cannot be moved or deleted, which lets a template owner fix a disclaimer or header in place while others edit the body.