TemplateProvider carries auth and template state. TemplateEditor renders the editing surface.
templateId does not resolve to one, so a first
render shows an empty editor rather than an error. Issue the token from your backend as
describes.
Restrict the channels
routing.channels decides which channel tabs appear. Unlisted channels are hidden from the
customer.
channels prop. It is deprecated in favour of routing.channels and
scheduled for removal, so pass routing. When both are set, routing.channels wins.
Switch templates
ChangetemplateId and the provider loads the new Template. The prop sits in an effect
dependency, so no remount or key is needed.
Publish from your own button
hidePublish removes the built-in control. useTemplateActions exposes the same action,
so your own button does the same work.
Control when writes happen
Auto-save is on, debounced 500ms. Turn it off to write on your own schedule.readOnly makes the editor read-only across every channel. It disables editing, toolbar
actions, block insertion, drag and drop, and auto-save, which makes it the prop to reach for
when a customer may view a Template but not change it.
Offer variables
variables populates the autocomplete a customer sees after typing {{.
variables unset disables every variable feature. The toolbar button is hidden
and typing {{ creates no variable chip. Nothing reports this, so an editor that looks
plain is usually an editor with no variables prop.
Two props change how strict that autocomplete is:
disableVariablesAutocompletedrops the dropdown and lets a customer type any name.variableValidationrestricts which names are allowed and says what happens when one fails.
sampleData is separate. It validates the data path on a loop, and warns when the path
matches no key or does not resolve to an array.
Theme the editor
theme takes a theme object or a class name. colorScheme selects light or dark.
@trycourier/react-designer/styles.css once in your app. Without it the editor
renders unstyled, which reads as a broken layout rather than a missing import.
Render inside a modal
The editor is a regular element, so your own dialog can hold it. Two things about the surrounding app matter. Give the container a height. The editor fills its parent, and a dialog that sizes to its content gives it nothing to fill. SetrenderToaster to false when your app already renders a Sonner <Toaster />.
The provider renders its own by default, and two on one page means every save message
appears twice.
Provider props
TemplateProvider holds auth, identity, and the options that outlive a single editor.
Editor props
Verify
Render the page and confirm the editor appears. Type into a block, wait for the save message, then open and confirm the Tenant’s Template carries the change.Troubleshooting
Limits & behavior
- Issue the token server-side. A browser holding your API key exposes the whole workspace.
hidePublishhides a button, nothing more. Publishing still works through the hook and through .routingis a UI restriction. It does not constrain what a stored Template may contain.readOnlystops auto-save. A read-only editor writes nothing, by design.
FAQ
How do I switch the customer to a different template?
How do I switch the customer to a different template?
Change the
templateId prop on TemplateProvider. The prop sits in an effect
dependency, so the provider loads the new Template without a remount.Can the editor run inside a dialog?
Can the editor run inside a dialog?
A dialog can hold the editor. Give the container an explicit height, and set
renderToaster to false if your app already renders a Sonner <Toaster />.Should I use channels or routing.channels?
Should I use channels or routing.channels?
Pass
routing.channels. The bare channels prop is deprecated and scheduled for
removal, and routing.channels takes priority when both are set.