Single-select autocomplete field with popup suggestions, canonical selected value, and component-owned empty-state localization.
Install @wyrd-company/react or the Flutter package and use it directly —
your DESIGN.md does the styling.
catalog/contracts/combobox.ymlsource of truth · verbatim
$schema: https://thewyrdingway.dev/schemas/component-contract.schema.ymlcontractVersion: 0.1.0identity:name: Comboboxtag: wyrd-comboboxpackage: wyrd.component.comboboxtitle: Comboboxsummary: Single-select autocomplete field with popup suggestions, canonical selected value, and component-owned empty-state localization.relationships:related-to: - collection-navigation - quality-parity-and-gatesclassification:category: form-fieldcomposition: collectioninteractive: truetarget-strategy:react: requiredflutter: requiredsurface:properties: - name: valuetype:kind: stringrequired: falsecontrolled: trueserializable: truesummary: Controlled selected option value; free-text values are not accepted. - name: default-valuetype:kind: stringrequired: falseserializable: truesummary: Initial uncontrolled selected option value. - name: optionstype:kind: arrayitem:kind: objectfields:value:kind: stringlabel:kind: stringdisabled:kind: booleanrequired: falsedefault: []serializable: truesummary: Ordered selectable option items; disabled items render but are skipped by navigation and activation. - name: placeholdertype:kind: stringrequired: falseserializable: truesummary: Placeholder text shown when no option is selected and no filter text is entered. - name: is-opentype:kind: booleanrequired: falsedefault: falsecontrolled: truereflects: trueserializable: truesummary: Controlled suggestion popup visibility. - name: default-opentype:kind: booleanrequired: falsedefault: falseserializable: truesummary: Initial uncontrolled suggestion popup visibility. - name: is-disabledtype:kind: booleanrequired: falsedefault: falsereflects: trueserializable: truesummary: Prevents text editing, popup opening, and option activation. - name: is-requiredtype:kind: booleanrequired: falsedefault: falsereflects: trueserializable: truesummary: Marks the field as requiring one selected option. - name: is-invalidtype:kind: booleanrequired: falsedefault: falsereflects: trueserializable: truesummary: Marks the selection as invalid and associates the error slot. - name: active-indextype:kind: integerminimum: 0required: falsedefault: 0serializable: truesummary: Initial active suggestion index when the popup opens.slots: - name: labelrequired: truecardinality: exactly-oneaccepts: - textsummary: Visible label and accessible-name source. - name: descriptionrequired: falsecardinality: zero-or-oneaccepts: - textsummary: Help text associated with the input. - name: errorrequired: falsecardinality: zero-or-oneaccepts: - textsummary: Validation error associated when is-invalid is true.events: - name: value-changepayload:value:kind: stringaction:kind: action-refbubbles: truecomposed: truecancelable: falsesummary: Canonical value-change event carrying the selected option value. - name: open-changepayload:is-open:kind: booleanreason:kind: enumvalues: - input - trigger - keyboard - dismiss - select - programmaticbubbles: truecomposed: truecancelable: falsesummary: Canonical suggestion popup visibility event. - name: option-selectpayload:index:kind: integervalue:kind: stringaction:kind: action-refbubbles: truecomposed: truecancelable: truesummary: Canonical suggestion activation event emitted once per accepted selection.states: - name: closedsource: behavior-runtimesummary: Suggestion popup is not visible. - name: opensource: behavior-runtimesummary: Suggestion popup is visible. - name: focusedsource: platformsummary: Text input owns focus. - name: selectedsource: propertysummary: State when value or default-value matches an option. - name: disabledsource: propertysummary: Disabled state derived from is-disabled. - name: invalidsource: propertysummary: Invalid state derived from is-invalid. - name: requiredsource: propertysummary: Required state derived from is-required.parts: - name: rootsummary: Field root and popup positioning owner.slots: - label - description - error - name: labelsummary: Label text.slots: - label - name: inputsummary: Editable combobox input control. - name: popupsummary: Suggestion popup surface. - name: optionsummary: Repeated suggestion option container. - name: empty-statesummary: Localized empty-state row shown when no option matches the filter. - name: descriptionsummary: Description text.slots: - description - name: errorsummary: Error text.slots: - errortokens:root:gap: spacing.xslabel:color: color.on-surfacetext: typography.label-mdinput:background: color.surfaceforeground: color.on-surfaceplaceholder: color.on-surface-variantborder-color: color.outlineborder-color-focus: color.primaryborder-color-invalid: color.errorborder-width: 1pxradius: rounded.smpadding-x: spacing.mdpadding-y: spacing.smtext: typography.body-mdpopup:background: color.surface-containerforeground: color.on-surfaceborder-color: color.outlineradius: rounded.mdshadow: shadow.mdpadding-y: spacing.xsoption:foreground: color.on-surfaceforeground-active: color.on-primarybackground-hover: color.secondarybackground-active: color.primary-hoverbackground-selected: color.secondarypadding-x: spacing.mdpadding-y: spacing.smempty-state:foreground: color.on-surface-variantpadding-x: spacing.mdpadding-y: spacing.smdescription:color: color.on-surface-varianttext: typography.body-mderror:color: color.errortext: typography.body-mdmessages: - key: combobox.no-optionsdescription: Empty-state text shown by the combobox popup when filtering leaves no matching options.obligations:accessibility:role: comboboxname: Label slot provides the accessible name.description: Description and error slots are programmatically associated with the input.keyboard: - Text input follows platform editing keys. - ArrowDown and ArrowUp open suggestions and move the active option, skipping disabled options. - Enter accepts the active enabled option when the popup is open. - Escape closes the popup without changing the selected value. - Tab leaves the field and closes the popup.semantics: - Input exposes combobox, expanded, autocomplete=list, aria-controls, and aria-activedescendant semantics on web. - Web listbox and option IDREF targets must live in the same root as the input. - Required, invalid, and disabled states are exposed through platform semantics. - Error text is associated only when invalid.behavior:model: collectioninteractions: - Typing filters options by label, opens the popup, and clears the active option when no enabled match remains. - Selecting an enabled option commits its value, emits option-select and value-change, closes the popup, and displays the selected option label. - Enter only commits an enabled option value; arbitrary filter text is not a value in v1. - Controlled value and is-open properties win over default-value and default-open.hostEffects: - Focus the input for keyboard entry. - Dispatch value-change, open-change, and option-select events. - Keep popup positioning synchronized with the input control.conditions: - rtl - reduced-motion - cvd-deuteranopia - density-compact - text-expansion - keyboard-insetsdui:status: serializableserializableProperties: - value - default-value - options - placeholder - is-open - default-open - is-disabled - is-required - is-invalid - active-indexserializableSlots: - label - description - erroreventBindings: - value-change - open-change - option-selectnotes: Option data, selected value, and open state serialize; popup positioning, focus, filtering query, and keyboard host effects remain target-local.examples: - name: emptystate: closedproperties:placeholder: Choose a spelloptions: - value: lightlabel: Light - value: shieldlabel: Shield - value: misty-steplabel: Misty Stepslots:label: Spelldescription: Pick the prepared spell to cast. - name: selectedstate: selectedproperties:default-value: shieldoptions: - value: lightlabel: Light - value: shieldlabel: Shield - value: misty-steplabel: Misty Stepslots:label: Spell - name: no-optionsstate: openproperties:is-open: trueoptions: []slots:label: Spelldescription: The popup shows the localized empty state when the typed filter has no matches.
01
Examples
Generated from the contract's examples block.
Previews are the published @wyrd-company/react component, themed by the
brand's role tokens — flip the site's light/dark toggle and they follow.
emptystate: closed
Usage
import { WyrdCombobox } from"@wyrd-company/react";
<WyrdCombobox placeholder="Choose a spell" options={[{"value":"light","label":"Light"},{"value":"shield","label":"Shield"},{"value":"misty-step","label":"Misty Step"}]} label="Spell" description="Pick the prepared spell to cast." />
// events: onValueChange, onOpenChange, onOptionSelect
import'package:wyrd_flutter/wyrd_flutter.dart';
WyrdCombobox(
placeholder: 'Choose a spell',
options: [{"value":"light","label":"Light"},{"value":"shield","label":"Shield"},{"value":"misty-step","label":"Misty Step"}],
label: Text('Spell'),
description: Text('Pick the prepared spell to cast.'),
)
// events: onChanged, onOpenChanged, onOptionSelect
import { WyrdCombobox } from"@wyrd-company/react";
<WyrdCombobox isOpen options={[]} label="Spell" description="The popup shows the localized empty state when the typed filter has no matches." />
// events: onValueChange, onOpenChange, onOptionSelect
import'package:wyrd_flutter/wyrd_flutter.dart';
WyrdCombobox(
isOpen: true,
options: [],
label: Text('Spell'),
description: Text('The popup shows the localized empty state when the typed filter has no matches.'),
)
// events: onChanged, onOpenChanged, onOptionSelect
02
Properties
Name
Type
Default
Summary
value
string
undefined
Controlled selected option value; free-text values are not accepted.
default-value
string
undefined
Initial uncontrolled selected option value.
options
array
Ordered selectable option items; disabled items render but are skipped by navigation and activation.
placeholder
string
undefined
Placeholder text shown when no option is selected and no filter text is entered.
is-open
boolean
false
Controlled suggestion popup visibility.
default-open
boolean
false
Initial uncontrolled suggestion popup visibility.
is-disabled
boolean
false
Prevents text editing, popup opening, and option activation.
is-required
boolean
false
Marks the field as requiring one selected option.
is-invalid
boolean
false
Marks the selection as invalid and associates the error slot.
active-index
integer
0
Initial active suggestion index when the popup opens.
03
Slots & events
Slot
Cardinality
Accepts
Summary
label
exactly-one
text
Visible label and accessible-name source.
description
zero-or-one
text
Help text associated with the input.
error
zero-or-one
text
Validation error associated when is-invalid is true.
Event
Payload
Summary
value-change
value, action
Canonical value-change event carrying the selected option value.
open-change
is-open, reason
Canonical suggestion popup visibility event.
option-select
index, value, action
Canonical suggestion activation event emitted once per accepted selection.
04
Tokens
The contract's token bindings. Open the shared contextual sidebar from any example;
primary swatches reflect the color you pick there. Error swatches show the active
preset's values; editing any knob switches to custom and resets error to TWW · Ink.
Binding
Token
root.gap
spacing.xs
label.color
color.on-surface
label.text
typography.label-md
input.background
color.surface
input.foreground
color.on-surface
input.placeholder
color.on-surface-variant
input.border-color
color.outline
input.border-color-focus
color.primary
input.border-color-invalid
color.error
input.border-width
1px
input.radius
rounded.sm
input.padding-x
spacing.md
input.padding-y
spacing.sm
input.text
typography.body-md
popup.background
color.surface-container
popup.foreground
color.on-surface
popup.border-color
color.outline
popup.radius
rounded.md
popup.shadow
shadow.md
popup.padding-y
spacing.xs
option.foreground
color.on-surface
option.foreground-active
color.on-primary
option.background-hover
color.secondary
option.background-active
color.primary-hover
option.background-selected
color.secondary
option.padding-x
spacing.md
option.padding-y
spacing.sm
empty-state.foreground
color.on-surface-variant
empty-state.padding-x
spacing.md
empty-state.padding-y
spacing.sm
description.color
color.on-surface-variant
description.text
typography.body-md
error.color
color.error
error.text
typography.body-md
05
States
State
Source
Summary
closed
behavior-runtime
Suggestion popup is not visible.
open
behavior-runtime
Suggestion popup is visible.
focused
platform
Text input owns focus.
selected
property
State when value or default-value matches an option.
disabled
property
Disabled state derived from is-disabled.
invalid
property
Invalid state derived from is-invalid.
required
property
Required state derived from is-required.
06
Accessibility
From the contract's accessibility obligations. Role combobox; Label slot provides the accessible name.
Text input follows platform editing keys.
ArrowDown and ArrowUp open suggestions and move the active option, skipping disabled options.
Enter accepts the active enabled option when the popup is open.
Escape closes the popup without changing the selected value.
Tab leaves the field and closes the popup.
Input exposes combobox, expanded, autocomplete=list, aria-controls, and aria-activedescendant semantics on web.
Web listbox and option IDREF targets must live in the same root as the input.
Required, invalid, and disabled states are exposed through platform semantics.