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

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

ClassAxisRules
form-selectbase-skinone required · exclusive
is-invalidmodifieroptional

Structure

SelectorRequiredDescription
optionrequiredNative <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-group
  • toolbars
  • filter 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

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

SelectorRequiredDescription
li.listbox-optionrequiredOption 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

OnAttributeLevelWhen
.listboxrolerequired
.listbox-optionrolerequired
.listboxaria-labelrecommendedAlways name the listbox: aria-label or aria-labelledby pointing at a visible caption.
.listbox-optionaria-selectedrecommendedSet 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-group
  • sidebars
  • cards
  • filter panels

Never inside (or containing):

  • .listbox