Diwa Design System

Multi Select

Multi Select allows users to choose one or more options 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 / SpaceToggle the currently highlighted option.
Escape / TabClose the dropdown and return focus to the trigger.

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="true"Options container — indicates multiple selection is allowed.
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 automatically to the filter input so users can type immediately. Keyboard navigation highlights options — each highlighted option receives focus via setFocus(). When the dropdown closes (Escape, Tab, or click-outside), focus returns to the trigger. The reset (✕) button is reachable by Tab when a selection exists.

WCAG 2.2 compliance

1.4.3 Contrast (Minimum) — AAPass

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

1.4.11 Non-text Contrast — AAPass

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

2.1.1 Keyboard — APass

Full keyboard navigation: Tab opens, arrow keys navigate options, Enter/Space toggles selection, Escape closes. The filter input and reset button are also keyboard-operable.

2.4.7 Focus Visible — AAPass

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

4.1.2 Name, Role, Value — APass

role="combobox", role="listbox", role="option", aria-expanded, aria-haspopup, aria-selected, aria-multiselectable, 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.
  • Filter performance — the filter input narrows options in real time. Ensure option labels are descriptive enough to be discoverable when typed partially, especially for screen reader users who cannot see the full list.