Skip to content

Tags

Every shortcut accepts an optional tags array — a free-form list of strings the engine attaches as metadata to the resulting widget. Tags don’t change rendering on their own; they’re hooks for Selectors to match against. The two together turn a tag into an addressable group: decorate every widget tagged 'identity' (or 'personal-info', or 'us-state') in one place instead of repeating the same prop on every shortcut.

gui.inputs.textInput('username', { label: 'Username' }, ['identity']);
gui.inputs.password('password', { label: 'Password' }, ['identity']);

The third positional argument on every shortcut is the tags array. A widget can carry as many tags as you like — selectors match against the list.

  • The same behavior or styling needs to apply to a logical group of widgets.
  • A selector should be reusable across forms (define once, drop into any form definition).
  • The alternative is repeating the same prop on many shortcuts.

The three demos below progress from the simplest possible use to a full payment form, so you can see how tags scale with the complexity of the form.

Three text inputs. The first two are tagged 'personal-info'; the third isn’t. A single selector adds a hint to every input carrying the tag — the untagged “Display name” input stays clean.

const form = [
gui.inputs.textInput('user.email', { label: 'Email' }, ['personal-info']),
gui.inputs.textInput('user.phone', { label: 'Phone' }, ['personal-info']),
gui.inputs.textInput('user.nickname', { label: 'Display name' }),
];
const formSelectors = [
gui.selectors
.tag('personal-info')
.inputs({ override: { hint: 'Personal data — never shared.' } }),
];

What just happened: the engine resolved each input, checked its tag list against the selector’s 'personal-info' matcher, and merged the hint decorator only for the matched widgets. Untagged widgets pass through untouched.

A sign-up form has two text inputs — a “Username” and a “Referral code” — but only the first should suppress browser autocomplete and carry a placeholder. Tagging the username with 'identity' lets a per-type selector decorate exactly that widget without touching the referral field.

const form = [
gui.inputs.textInput('username', { label: 'Username' }, ['identity']),
gui.inputs.textInput('referral', { label: 'Referral code' }),
];
const formSelectors = [
gui.selectors.tag('identity').textInputs({
override: {
autocomplete: 'off',
placeholder: 'Pick a sign-in name',
},
}),
];

Both widgets are the same kind, but only the first carries the tag — so the selector’s matcher fires on it alone. A tag isn’t only a “group of widgets” device: it’s also the simplest way to address one widget out of several identical ones, without having to give it a uid and reach for a byUid selector.

Payment details with shared dropdown options

Section titled “Payment details with shared dropdown options”

The case where the user-facing payoff really lands. A payment form has both a delivery address and an invoice address. Each address has a State select. Without tags you’d hard-code the same fifty US states twice — or pull them out into a shared constant and pass it into both widgets manually. With tags + selectors, both selects carry the 'us-state' tag and a single selector populates options once.

A small helper builds the address fields, and a gui.layouts.tabs(...) separates the two addresses cleanly into their own panels — no fake-heading widgets in the form, the layout itself provides the section labels.

const addressBlock = (kind: 'delivery' | 'invoice') => [
gui.inputs.textInput(`${kind}.street`, { label: 'Street' }),
gui.layouts.flex([
gui.inputs.textInput(`${kind}.city`, { label: 'City' }),
gui.inputs.dropdown(`${kind}.state`, { label: 'State' }, ['us-state']),
gui.inputs.textInput(`${kind}.zip`, { label: 'ZIP' }),
]),
];
const form = [
gui.layouts.tabs([
{ label: 'Delivery address', children: addressBlock('delivery') },
{ label: 'Invoice address', children: addressBlock('invoice') },
]),
];
const formSelectors = [
gui.selectors.tag('us-state').dropdowns({
override: {
items: US_STATES,
labelField: 'label',
valueField: 'value',
height: 180,
},
}),
];

Switch tabs — both State dropdowns share the same fifty items and the same labelField / valueField config, all defined once in the selector. Add a third address (billing, shipping, whatever) and you don’t touch the selector at all: tag the new State dropdown with 'us-state' and it inherits everything.

  • Selectors — chaining tags with type selectors and scope operators.
  • gui.selectors reference — every leaf method (inputs, textInputs, selects, …) you can pin a tag to.