Settings modal
A widget can declare a settings modal: your properties grouped onto tabs in a modal, with an optional live preview beside them. The streamer opens it from the Overlay Editor's properties panel.
It's optional. Most widgets don't need one. Reach for it when a widget has many settings, or when seeing a change as you make it matters more than a form in a side panel.
A widget can have up to four modals, each with its own card, button, tabs and preview. One is usually enough. Add a second when settings split into separate jobs, such as how the widget looks and how it behaves.
Set it up in the Workshop
- Open your widget, then the Properties surface.
- Scroll to Settings modals at the bottom of the property list, under Layout, and click Add settings modal.
- Fill in the fields:
| Field | Meaning |
|---|---|
| Title | The modal's heading, and the title of the card in the properties panel. Up to 60 characters. |
| Id | Lowercase letters and numbers joined by single hyphens, unique among the widget's modals. |
| Button label | The text on the panel button that opens the modal. Up to 40 characters. |
| Tabs | Up to 12. See below. |
Each tab has:
| Field | Meaning |
|---|---|
| Label | The tab's name. |
| Id | Lowercase letters and numbers joined by single hyphens, such as look-and-feel. Unique across all of the widget's modals. The preview reads it. |
| Groups | The property group names shown on this tab, in order. A group can be on only one tab, in any modal. A tab with several groups shows each group as a sub-heading. |
| Indicator | Optional. A switch (boolean) property. Its value lights an on/off dot on the tab. |
Move tabs up or down to reorder them. You can remove any tab except a modal's last one. To get rid of that, remove the modal.
A group name comes from the Group field on your properties. If a group is listed on a tab but no property uses it any more, it shows struck out with "No fields use this group".
What streamers see
- Groups placed on tabs leave the properties panel. Each modal gets a card in the panel with its title and button.
- Properties whose group is on no tab stay in the panel.
- The panel's search still finds properties on tabs. Each match shows on the card with its tab, and clicking it opens the modal on that tab with the property highlighted.
- In the modal, fields behave exactly like the panel: variants, dynamic values and required markers all work.
- A field whose visibility condition is false stays in place but is disabled. It isn't hidden.
- Edits apply immediately. There's a Done button and no save or cancel.
Live preview
Turn on Live preview for a modal in the designer to show your widget beside its fields. Each modal has its own preview switch and size.
- Width and Height are optional, from 100 to 3840 px. Leave them blank to use the placement's own size.
- The preview renders at that logical size, then scales to fit the column. Proportions match the stream.
- It's display only. Nothing in it can be clicked.
Choose what the preview draws
In your core file, call showSettingsPreviewTemplate next to showTemplate and showEditorTemplate:
// main.ts
import { onLoad, showTemplate, showEditorTemplate, showSettingsPreviewTemplate, Template } from '@widget';
onLoad(() => {
showTemplate(Template.Main);
showEditorTemplate(Template.Main);
showSettingsPreviewTemplate(Template.Preview);
});
Rules:
- Until you call it, the preview shows your editor template (
showEditorTemplate). - If nothing paints, the preview shows "No preview".
showTemplateis ignored in the preview.- Once the preview template is shown, later
showEditorTemplatecalls are ignored there.
Templates can't import other templates. If the live and preview templates share UI, put it in a code file and import it from both.
React to the open tab
useSettingsPreviewFocus() returns { tab, field }:
tabis the id of the open tab. Tab ids are unique across a widget's modals, so it also tells you which modal is open.fieldis the property under the pointer or holding focus, as its JS name. This is the nameuseProptakes, so the keybubble-colorgivesbubbleColor.
Either can be null. Outside the preview it always returns { tab: null, field: null }.
Simulate an event
simulateEvent(event, payload?) feeds your widget a sample event, as if it just happened. Use it to show a moving part of your widget when the streamer opens a tab.
// preview.tsx
import { useEffect } from 'react';
import { Event, simulateEvent, useLatestEvent, useProp, useSettingsPreviewFocus } from '@widget';
export default function Preview() {
const { tab, field } = useSettingsPreviewFocus();
const bubbleColor = useProp('bubbleColor');
const chat = useLatestEvent(Event.Chat);
useEffect(() => {
if (tab === 'messages') simulateEvent(Event.Chat, { text: 'hello!' });
}, [tab]);
return (
<div style={{ outline: field === 'bubbleColor' ? '2px solid white' : 'none' }}>
<span style={{ background: bubbleColor }}>{chat?.text ?? 'Waiting for chat'}</span>
</div>
);
}
How it works:
- The payload is a built-in sample for that event. It's available for each binding your widget declares.
- Your
payloadis shallow-merged over the sample. - Every call gets fresh ids (
messageId,eventId,alertId,spinId) unless you pass them, and the currentreceivedAt. - The event arrives on the next microtask through the normal path.
useEvent,useLatestEvent,useBinding,<Bind>, CSS variables andregisterBindinghandlers all see it.
It works only in the settings preview and the Workshop's own preview. On the Overlay Editor canvas and on a live overlay it warns once and does nothing.
simulateEvent skips the host-side steps of a real delivery: dynamic-value re-resolution, variants and alert handling. For an alert-style widget, draw the alert state directly in the preview instead of simulating the trigger.
Limits
- The preview can't touch real state. Saved data (
useStore) stays in memory, andsetPropertyand other capabilities don't persist there. - No live chat or events reach the preview. Use
simulateEvent. - Up to four modals, with up to 12 tabs each. A group can be on only one tab, in any modal.
Test it in the Workshop
On the Properties surface, click Open settings modal on a modal in the designer. It opens the real modal with your Simulate test values. It previews your current unbuilt draft, which is compiled when the modal opens. Preview logs appear in the Workshop console.
When you publish, installed copies get the modal.
Next
- Property schema — define the fields and groups.
- The @widget runtime — the full code API.