States
States are named boolean expressions over the live form data. Declare them once in formConfig.states, then reference the names from include / exclude rules, per-state property overrides, and selectors.
const formConfig = { states: { hasDiscount: '$form.hasDiscountCode === true', isAdult: '$form.driverAge >= 18', },};Expression syntax
Section titled “Expression syntax”Expressions are JavaScript-like. The engine exposes:
$form— the current form data tree.- Standard operators:
&&,||,!,===,!==,<,>,<=,>=,+,-,*,/,?:. - Optional chaining:
$form.user?.name.
Expressions can reference any path in the form data.
Where to use states
Section titled “Where to use states”- In
include/excluderules: gate widgets. - In per-state property overrides on shortcuts: change props when active.
- In
gui.selectors.state(...)chains: scope a selector to one state.
Gating with include / exclude / when
Section titled “Gating with include / exclude / when”Two properties on every shortcut control whether a widget renders:
| Property | Shape |
|---|---|
include | { in: ['stateName', ...] } — render when any named state is active. Or { when: '<expr>' } — render only when the expression is truthy. |
exclude | { from: ['stateName', ...] } — render unless any of the named states are active. Or { when: '<expr>' } — render unless the expression is truthy. |
Note the field names — include uses in, exclude uses from. Both also accept when for inline expressions that don’t need a name.
When to use each
includewithin— the condition has a name and is used in multiple places (gating, prop overrides, selectors).includewithwhen— a one-off condition, expressed inline, not worth declaring a state for.exclude— when “hide-when X” reads more naturally than “show-unless X”.
Putting it together — a support-ticket form
Section titled “Putting it together — a support-ticket form”The demo below shows the three gating mechanisms working side by side:
include: { in: ['isBug'] }on the Steps to reproduce textarea — render only when the named state is active.include: { in: ['isBug', 'isBilling'] }on the Priority radiogroup — render when any of the listed states is active (OR semantics).exclude: { from: ['isBilling'] }on the Marketing opt-in checkbox — render unless the named state is active.include: { when: '$form.subscribeNewsletter === true' }on the Newsletter frequency radiogroup — an inline reactive expression for a one-off condition where naming a state would be overkill.
import { gui } from '@golemui/gui-shared';
const formDef = [ gui.inputs.radiogroup('issueType', { label: 'What can we help you with?', options: [ { value: 'bug', label: 'Bug report' }, { value: 'billing', label: 'Billing question' }, { value: 'feature', label: 'Feature request' }, { value: 'other', label: 'Other' }, ], direction: 'row', }),
gui.inputs.textarea('description', { label: 'Description', placeholder: 'Tell us what happened…', }),
// include — only render when isBug is active. gui.inputs.textarea('reproSteps', { label: 'Steps to reproduce', placeholder: '1. Go to …\n2. Click …\n3. Notice …', include: { in: ['isBug'] }, }),
// include with multiple states — render when ANY is active. gui.inputs.radiogroup('priority', { label: 'Priority', options: [ { value: 'low', label: 'Low' }, { value: 'medium', label: 'Medium' }, { value: 'high', label: 'High' }, ], direction: 'row', include: { in: ['isBug', 'isBilling'] }, }),
// exclude — render unless isBilling is active. gui.inputs.checkbox('marketingOk', { label: 'You may share my email with our partners.', exclude: { from: ['isBilling'] }, }),
// inline `when` — no named state needed for a one-off condition. gui.inputs.booleanInput('subscribeNewsletter', { label: 'Subscribe to the product newsletter', }), gui.inputs.radiogroup('newsletterFrequency', { label: 'How often?', options: [ { value: 'weekly', label: 'Weekly' }, { value: 'monthly', label: 'Monthly' }, ], direction: 'row', include: { when: '$form.subscribeNewsletter === true' }, }),
gui.actions.button({ label: 'Submit ticket', actionType: 'submit' }),];
const formConfig = { states: { isBug: '$form.issueType === "bug"', isBilling: '$form.issueType === "billing"', },};Try it: switch the issue type and watch the Steps to reproduce appear/disappear (named-state include), the Priority show for both Bug and Billing (multi-state include), and the marketing opt-in disappear when you pick Billing (named-state exclude). Then toggle the newsletter switch — the frequency radio uses an inline when expression with no named state at all.
See also
Section titled “See also”- Features / States — gating, per-state property overrides, composing states.
- Runtime Functions — when a one-off prop should react to data per-render rather than via a named state.