Chaining
The selector chain is a small immutable builder. Each scope method (tag, state, tagsAnd, tagsOr) returns a new chain with that scope appended; the leaf method (inputs, dropdowns, etc.) emits the matched selector.
gui.selectors .tag('identity') .state('loaded') .inputs({ override: { disabled: false } });Reads as: for inputs tagged identity, while the loaded state is active, set disabled: false.
A chained selector in action
Section titled “A chained selector in action”A small profile form. The three personal-info inputs are tagged 'profile-field'. By default they’re locked; flipping the Edit mode toggle activates the editing state, which unlocks them through a chained .tag('profile-field').state('editing').inputs(...) selector.
const formDef = [ gui.inputs.booleanInput('editMode', { label: 'Edit mode' }), gui.inputs.textInput('name', { label: 'Name' }, ['profile-field']), gui.inputs.textInput('email', { label: 'Email' }, ['profile-field']), gui.inputs.textInput('phone', { label: 'Phone' }, ['profile-field']),];
const formConfig = { states: { editing: '$form.editMode === true', },};
const formSelectors = [ // Default: lock every tagged profile field. gui.selectors.tag('profile-field').inputs({ override: { disabled: true }, }), // While `editing` is active, unlock the same fields. gui.selectors .tag('profile-field') .state('editing') .inputs({ override: { disabled: false }, }),];The first selector matches every input carrying the profile-field tag and disables it. The second selector adds a tighter scope — state('editing') — so it only fires when the toggle is on, and its disabled: false override beats the broader rule by precedence (state-scoped > tag-scoped). Toggle the switch to lock and unlock all three fields at once.
Order matters
Section titled “Order matters”Scope operators commute in semantics — tag('x').state('y') and state('y').tag('x') produce the same matcher — but the convention is tag first, state second, for readability.
The chain builder is immutable, so you can save partial chains and reuse them. Here’s the same demo above refactored to share a profileField chain root:
const profileField = gui.selectors.tag('profile-field');
const formSelectors = [ profileField.inputs({ override: { disabled: true } }), profileField.state('editing').inputs({ override: { disabled: false } }),];Identical output — the partial chain just keeps the tag scope from being repeated.
See also
Section titled “See also”- Scope operators —
tagandstatesemantics. - Multi-value scopes —
tagsAnd,tagsOr. - Precedence — how stacked rules combine.