Diwa Design System

Select

Select allows users to choose a single option from a filterable dropdown list. Supports keyboard navigation, validation states, and dense mode (compact) for space-constrained layouts.

Keyboard interaction

KeyAction
TabMove focus to the trigger button.
Shift + TabMove focus away from the component.
Enter / Space / ↓ / ↑Open the dropdown when the trigger is focused.
↓ Arrow DownMove keyboard highlight to the next visible option.
↑ Arrow UpMove keyboard highlight to the previous visible option.
HomeMove keyboard highlight to the first visible option.
EndMove keyboard highlight to the last visible option.
Enter / SpaceSelect the highlighted option and close the dropdown.
Escape / TabClose the dropdown without changing the selection.

Screen reader behaviour

Attribute / PropertyValue / Behaviour
role="combobox"Trigger div — identifies the toggle as a combobox control.
aria-haspopup="listbox"Trigger div — announces that activating opens a listbox.
aria-expandedTrigger div — reflects whether the dropdown is open (true/false).
aria-controlsTrigger div — points to the listbox element by ID.
aria-labelledbyTrigger div — associates the visible label with the combobox.
aria-requiredTrigger div — set when required={true}.
aria-invalid="true"Trigger div — set when state="error".
aria-describedbyTrigger div — points to the message element when visible.
role="listbox"Options container — identifies the dropdown as a listbox.
aria-multiselectable="false"Options container — indicates single selection only.
role="option"Each option row — identifies each item as a selectable option.
aria-selectedEach option row — reflects the current selected state (true/false).
aria-disabledEach option row — set on individual disabled options.

Focus management

When the dropdown opens, focus moves to the filter input. Selecting an option closes the dropdown and returns focus to the trigger automatically. Escape and Tab also return focus to the trigger.

WCAG 2.2 compliance

1.4.3 Contrast (Minimum) — AAPass

Trigger text and option labels use --diwa-text-primary; meet the 4.5:1 minimum contrast ratio against the component background in both themes.

1.4.11 Non-text Contrast — AAPass

The trigger border (--diwa-border) and selected option indicator (--diwa-accent) meet ≥ 3:1 contrast against adjacent surface colours.

2.1.1 Keyboard — APass

Full keyboard navigation: Tab opens, arrow keys highlight options, Enter/Space selects, Escape closes without selection change.

2.4.7 Focus Visible — AAPass

A tokenized focus outline (var(--diwa-focus-ring-width) solid --diwa-border-focus) is shown on the trigger via :focus-visible.

4.1.2 Name, Role, Value — APass

role="combobox", role="listbox", role="option", aria-expanded, aria-haspopup, aria-selected, and aria-required are all managed automatically.

Best practices

  • Reduced motion — all CSS transitions inside the shadow DOM respond to prefers-reduced-motion: reduce and are suppressed automatically.
  • Always provide a label — the label prop is required for an accessible control. Set hide-label only when a visible label cannot fit the layout — the text is still present in the accessibility tree.
  • Error messaging — always pair state="error" with a meaningful message prop — colour alone is insufficient for users who cannot distinguish red from other colours.