Select
Customizable select: a native <select class="form-select select"> progressively enhanced with `appearance: base-select`. Supporting browsers render the picker as a styled overlay panel (dropdown-menu skin, styled options and checkmark); other browsers keep the fully native picker with the .form-select field skin. No extra markup and no JavaScript — semantics, keyboard, and AT behavior stay native in both modes.
Root: select.select on <select>
Example
<select class="form-select select" id="status" aria-label="Status"><option>To do</option><option selected>In progress</option><option>Done</option></select>
Contract
Variants & modifiers
| Class | Axis | Rules |
|---|---|---|
form-select | base-skin | one required · exclusive |
is-invalid | modifier | optional |
Structure
| Selector | Required | Description |
|---|---|---|
option | required | Native <option> children (optionally inside <optgroup>). In base-select mode each option renders as a menu row with hover/checked/disabled states and a trailing ::checkmark on the checked one. |
Accessibility
Must have an associated <label> (for/id) or aria-label. Because the control stays a real <select>, no ARIA is needed — roles, keyboard, and screen-reader behavior are native in both the enhanced and fallback rendering. Do not replace this with a scripted .dropdown for form input.
Nesting
Allowed in:
.form-grouptoolbarsfilter rows
Subcomponents
Listbox
Always-open listbox: a static ul/li list styled like an open picker panel, for pick-lists that stay visible (sidebars, transfer lists, command palettes). Selection is conveyed twice: the .selected class (or aria-selected="true") for styling, and aria-selected for AT. Purely presentational + ARIA — it ships no keyboard behavior of its own.
Root: .listbox on <ul>
Example
- accessibility
- design-system
- legacy
<ul class="listbox" role="listbox" aria-label="Labels"><li class="listbox-option" role="option" aria-selected="false">accessibility</li><li class="listbox-option selected" role="option" aria-selected="true">design-system</li><li class="listbox-option disabled" role="option" aria-disabled="true" aria-selected="false">legacy</li></ul>
Structure
| Selector | Required | Description |
|---|---|---|
li.listbox-option | required | Option rows. States: .selected (or aria-selected="true") for the chosen row, .disabled (or aria-disabled="true") for inert rows — the CSS matches both the class and the ARIA attribute, so keeping them in sync styles for free. |
Accessibility
| On | Attribute | Level | When |
|---|---|---|---|
.listbox | role | required | |
.listbox-option | role | required | |
.listbox | aria-label | recommended | Always name the listbox: aria-label or aria-labelledby pointing at a visible caption. |
.listbox-option | aria-selected | recommended | Set aria-selected on every option (true/false) whenever the listbox represents a selection, and keep it in sync with the .selected class. |
role="listbox" on the <ul> and role="option" on each <li> are required. If users are meant to change the selection, you must script focus management (tabindex, arrow keys) and aria-selected updates yourself — for plain form input prefer the native <select> (or <select multiple>) above, which gets all of that for free. Without scripting, treat this as a read-only representation of a selection.
Nesting
Allowed in:
.form-groupsidebarscardsfilter panels
Never inside (or containing):
.listbox