Sensible defaults
The DX layer applies a small set of sensible defaults to keep your form definitions concise:
| Default | Behavior |
|---|---|
| Auto-label | If you don’t set label, the engine derives one from path (e.g. firstName → First Name). |
| Auto-placeholder | If you don’t set placeholder, the engine uses path as a placeholder. |
| Auto-stack | If your formDef has multiple top-level items and no top-level layout, the engine wraps them in a vertical flex. |
Auto-label
Section titled “Auto-label”Every input shortcut that takes a path (gui.inputs.textInput, numberInput, booleanInput, password, currency, textarea, markdown, checkbox, radiogroup, select, dropdown, list, calendar, dateInput, datePicker, rangeCalendar, rangeDateInput, rangeDatePicker, custom) runs its path through a single transform when no label is set:
- Split before each uppercase letter —
firstName→first Name. - Replace runs of
_or-with a space —first_name,first-name→first name. - Collapse and trim whitespace.
- Title-case each word.
The transform doesn’t touch dots in the path, so a nested path keeps its dot in the derived label:
path | Derived label |
|---|---|
name | Name |
firstName | First Name |
first_name | First Name |
first-name | First Name |
user.firstName | User.First Name |
a.b.c | A.B.C |
If you want only the leaf segment as the label, set it explicitly: gui.inputs.textInput('user.firstName', { label: 'First name' }).
When the derivation runs
Section titled “When the derivation runs”For each input, the engine derives a label only when all of these are true:
labelwas not passed (it’sundefinedornull).suppressAutomaticLabelsis not on for that input (via selector).pathis non-empty.
Anything else — including label: '' — is kept as-is.
Overriding
Section titled “Overriding”Pass label on the call site. It always wins over the derivation:
gui.inputs.textInput('firstName', { label: 'Given name' }); // → 'Given name'You can also use a Localizable for i18n: label: { key: 'user.firstName.label', default: 'First name' }.
Suppressing on a single input
Section titled “Suppressing on a single input”Pass an empty-string label. The check looks for label != null, so '' counts as “you set it”:
gui.inputs.textInput('firstName', { label: '' }); // → '' (no label rendered)Suppressing globally
Section titled “Suppressing globally”Use a selector. Scope it as broadly or narrowly as you need:
const formSelectors = [ // Turn off auto-labels on every input. gui.selectors.inputs({ suppressAutomaticLabels: true }),
// Re-enable only for inputs tagged 'identity'. gui.selectors.tag('identity').inputs({ suppressAutomaticLabels: false }),];Same precedence rules as every other selector apply — see Precedence.
JSON forms
Section titled “JSON forms”Auto-label is a DX-layer feature. Raw JSON form definitions go through a different path: the label you set in JSON is the label rendered, and an absent label stays absent.
Auto-placeholder
Section titled “Auto-placeholder”Same shape as auto-label, but the value used is the raw path (no transform). The same path != null rules apply, with suppressAutomaticPlaceholders to disable.
Auto-stack
Section titled “Auto-stack”If your formDef has multiple top-level items and no wrapping layout, the engine wraps them in a vertical flex layout so the form renders as a single column. Wrap them yourself (e.g. gui.layouts.flex(..., { direction: 'row' })) to opt out, or set suppressAutomaticStack: true in formConfig for the whole form.
Demo: suppression in practice
Section titled “Demo: suppression in practice”const formDef = [ gui.layouts.flex( [ gui.inputs.textInput('username', undefined, ['identity']), gui.inputs.textInput('firstName'), gui.inputs.textInput('lastName'), ], { direction: 'column', gap: 12 }, ),];
const formSelectors = [ // suppress auto-labels and auto-placeholders on every input gui.selectors.inputs({ suppressAutomaticLabels: true, suppressAutomaticPlaceholders: true, }),
// override that suppression for inputs tagged 'identity' gui.selectors.tag('identity').inputs({ suppressAutomaticPlaceholders: false, }),];What you should see in the demo:
- No labels on any of the three inputs —
suppressAutomaticLabelsis on for every input. - No placeholder on
firstNameorlastName—suppressAutomaticPlaceholdersis on for every input. - A
usernameplaceholder on the first field — the tag-scoped selector re-enables auto-placeholders for inputs tagged'identity', beating the broader rule by precedence.
See also
Section titled “See also”- Precedence — where defaults sit in the merge order.
gui.selectorsreference — every selector and config flag.