Combobox
A text field for picking one option from a long list: typing filters the options, and the chosen option's value submits with the form. Use it when there are too many options to scan comfortably (roughly more than ten), or when the options come from a search.
Intents
form-field
selection
text-entry
Variants
Every value of the attributes that change how it looks. The values come from the schema.
size
Field size, matching aihio-input.
size="sm"size="md"size="lg"Examples
Each one rendered live, over the markup that produces it.
A searchable list
Typing filters without regard to case or accents.
<aihio-field>
<label slot="label">Country</label>
<aihio-combobox name="country" placeholder="Search countries">
<aihio-option value="fi">Finland</aihio-option>
<aihio-option value="fr">France</aihio-option>
<aihio-option value="de">Germany</aihio-option>
<aihio-option value="is">Iceland</aihio-option>
<aihio-option value="no">Norway</aihio-option>
<aihio-option value="se">Sweden</aihio-option>
<aihio-option value="ax">Åland Islands</aihio-option>
</aihio-combobox>
<span slot="description">Type to filter. Accents are optional.</span>
</aihio-field>
Rich options and a preset value
label sets the text shown once an option is chosen; a disabled option cannot be.
<aihio-field>
<label slot="label">Assignee</label>
<aihio-combobox name="assignee" value="ada">
<aihio-option value="ada" label="Ada Lovelace">Ada Lovelace <small>Engineering</small></aihio-option>
<aihio-option value="grace" label="Grace Hopper">Grace Hopper <small>Compilers</small></aihio-option>
<aihio-option value="alan" label="Alan Turing" disabled>Alan Turing <small>On leave</small></aihio-option>
</aihio-combobox>
</aihio-field>
Free text allowed
allow-custom keeps text that matches no option.
<aihio-field>
<label slot="label">Tag</label>
<aihio-combobox name="tag" allow-custom placeholder="Pick or type a tag">
<aihio-option>bug</aihio-option>
<aihio-option>design</aihio-option>
<aihio-option>documentation</aihio-option>
</aihio-combobox>
</aihio-field>
Options from a server
filter="none" leaves filtering to you: listen for aihio-search and replace the options.
<aihio-combobox aria-label="Search users" name="user" filter="none" empty-text="Type to search"></aihio-combobox>
Mistakes
Each one beside its fix, with what aihio lint says about it. The prompt fragment gives agents the
same pairs, and the build fails if the linter stops catching one or a fix stops passing.
Placeholder is not a label.
Wrap it in aihio-field with a label slot, or add aria-labelledby or aria-label.
Don't
<aihio-combobox placeholder="Country">
<aihio-option value="fi">Finland</aihio-option>
</aihio-combobox>
aihio lint reports
-
combobox-labelerror
Do
<aihio-field>
<label slot="label">Country</label>
<aihio-combobox name="country">
<aihio-option value="fi">Finland</aihio-option>
</aihio-combobox>
</aihio-field>
A wrapping <label> takes its name from all of its text, so an open list's options become part of the field's name.
Use aihio-field instead.
Don't
<label>
Country
<aihio-combobox>
<aihio-option value="fi">Finland</aihio-option>
</aihio-combobox>
</label>
aihio lint reports
-
combobox-labelerror
Do
<aihio-field>
<label slot="label">Country</label>
<aihio-combobox name="country">
<aihio-option value="fi">Finland</aihio-option>
</aihio-combobox>
</aihio-field>
Native <option> elements are not read.
Use aihio-option.
Don't
<aihio-combobox aria-label="Size">
<option value="s">Small</option>
<option value="m">Medium</option>
</aihio-combobox>
aihio lint reports
-
invalid-childerror -
invalid-childerror
Do
<aihio-combobox aria-label="Size">
<aihio-option value="s">Small</aihio-option>
<aihio-option value="m">Medium</aihio-option>
</aihio-combobox>
An option without a value uses its label as its value, so both options have the value "Pro" and the second can never be told apart from the first.
Don't
<aihio-combobox aria-label="Plan">
<aihio-option>Pro</aihio-option>
<aihio-option value="Pro">Pro (annual)</aihio-option>
</aihio-combobox>
aihio lint reports
-
combobox-option-valueserror
Do
<aihio-combobox aria-label="Plan">
<aihio-option value="pro">Pro</aihio-option>
<aihio-option value="pro-annual">Pro (annual)</aihio-option>
</aihio-combobox>
API
Every attribute, property, method, and event the schema declares for aihio-combobox.
Attributes
value- string
- Value of the initially chosen option, and the value a form reset returns to. The value property carries the live choice.
name- string
- Form field name. The chosen option's value (not its label) is submitted under it. Without it the field submits nothing.
form- string
- Id of an external form that owns the field.
placeholder- string
- Placeholder text. It is not a label.
disabled-
boolean
default
false - Disables the field. A disabled field submits nothing.
readonly-
boolean
default
false - Shows the chosen option without letting it change. The value still submits.
required-
boolean
default
false - Requires a choice for native constraint validation.
error-
boolean
default
false - Shows error styling and sets aria-invalid.
aihio-fieldsets this from its error slot. size-
one of
smmdlgdefaultmd - Field size, matching
aihio-input. filter-
one of
containsstarts-withnonedefaultcontains - How typing filters the options. contains ranks prefix matches first, then word-start matches, then any match. none shows every option as given, for lists filtered by a server.
allow-custom-
boolean
default
false - Accepts typed text that matches no option; the text becomes the value. Without it, leaving the field reverts unmatched text to the chosen option.
loading-
boolean
default
false - Shows a loading row and marks the list busy while options are being fetched.
empty-text-
string
default
No results - Shown and announced when no option matches.
loading-text-
string
default
Loading… - Shown and announced while loading is set.
results-text- string
- Result-count announcement with a {count} placeholder, for localisation (e.g. "{count} tulosta"). Defaults to "1 result" / "N results".
open-
boolean
default
false - Reflects whether the list is showing. Set or remove it to open or close the list.
Properties
value-
string - Get or set the chosen option's value (or the free text, with allow-custom). Setting it does not fire
aihio-change. defaultValue-
string - Get or set the reset value reflected by the value attribute
selectedOption-
HTMLElement | nullread-only - The chosen
aihio-option, or null control-
HTMLInputElement | nullread-only - The native text input carrying
role="combobox" form-
HTMLFormElement | nullread-only - The owning form, or null outside one
validity-
ValidityState | nullread-only - Native constraint validation state
validationMessage-
stringread-only - Native validation message
willValidate-
booleanread-only - Whether the field participates in constraint validation
Methods
open(): void- Opens the list showing every option, with the chosen one highlighted.
close(): void- Closes the list, reverting unconfirmed text to the chosen option.
toggle(): void- Opens or closes the list.
focus(options?: FocusOptions): void- Moves focus to the text input.
checkValidity(): boolean- Runs native constraint validation and returns whether the field is valid.
reportValidity(): boolean- Runs native constraint validation and shows the browser message if invalid.
setCustomValidity(message: string): void- Sets a custom validation message.
Events
aihio-change-
detail
{ value: string, label: string } - Fired when the person commits a different choice, or when a form reset changes it. Not fired for programmatic value changes.
aihio-search-
detail
{ query: string } - Fired on every keystroke with the typed text. Use it to fetch options for
filter="none". aihio-open- Fired after the list opens.
aihio-close-
detail
{ reason: string } - Fired after the list closes.
Composition
- Allowed children
-
aihio-option
Sub-components
Used only inside aihio-combobox, which gives them their roles and keyboard behaviour.
<aihio-option>
One choice in an aihio-combobox. Its text (or label attribute) is what typing matches and what the field shows once chosen.
Attributes
value- string
- Submitted value. Defaults to the label.
label- string
- Text matched against and shown in the field when the content is richer than a plain label (an icon, a secondary line).
disabled-
boolean
default
false - Shown but cannot be chosen, and skipped by the arrow keys.
Properties
value-
string - The value attribute, or the label when it is absent
label-
string - The label attribute, or the normalised text content
disabled-
boolean - Reflects the disabled attribute
selected-
booleanread-only - Whether the owning combobox has this option chosen
Accessibility
What you have to provide, and what the component already does. The obligations with a rule are checked by
aihio lint and by the dev build's console warnings.
Your obligations
-
error When the combobox is not inside anaihio-fieldLabel it with aria-labelledby pointing at visible text, or aria-label. Placeholder is not a label, and a wrapping
<label>would fold the option text into the field's name.Checked as
combobox-label -
error When twoaihio-optionchildren share a valueGive every option a distinct value; the value is how the chosen option is found again.
Checked as
combobox-option-values -
warn When the combobox is inside a<form>and its value should be submittedSet name. A combobox without a name is omitted from FormData.
Checked as
combobox-form-name
Handled for you
- A real
<input role="combobox">witharia-autocomplete="list", aria-expanded, and aria-controls pointing at the listbox - DOM focus stays in the input; aria-activedescendant follows the highlighted option, in the same tree as the options it names
- Options render as
role="option"insiderole="listbox"; the chosen option hasaria-selected="true"and a check mark, disabled options have aria-disabled - ArrowDown/ArrowUp open the list and move through enabled options (wrapping); Alt+ArrowDown opens without moving; Alt+ArrowUp accepts and closes; PageDown/PageUp jump ten
- Enter chooses the highlighted option; Escape closes and reverts unconfirmed text, and is left alone when the list is closed so a surrounding dialog still closes
- Tab accepts the highlighted option and moves on; leaving the field any other way keeps the previous choice unless the text matches an option exactly
- Typing filters case- and accent-insensitively ("aland" finds "Åland"), ranks prefix matches first, highlights the first match, and sets the matched text in bold
- A polite status region announces the result count, the empty message, or the loading message once typing pauses
- The toggle button is out of the tab order, carries the field's label, and exposes aria-expanded
- Keys pressed while an IME is composing are left to the IME
- The chosen value submits through a hidden input under name; required, form reset,
<fieldset disabled>, and the form attribute behave natively - The list renders in the top layer, flips above the field when there is more room there, and fits the visual viewport above an on-screen keyboard
- Forced colours restate the highlighted and disabled states with system colours; reduced motion removes the open animation and spinner