Accessibility
The roles, labels and live regions that make the widget usable with a screen reader, and what to check.
The widget implements the ARIA combobox pattern end to end, inside its shadow root.
Roles and attributes
| Element | Role / attribute |
|---|---|
| The input | role="combobox", aria-expanded, aria-controls pointing at the results list, aria-activedescendant pointing at the highlighted result's id |
| The results container | role="listbox" |
| Each result | role="option", aria-selected on the highlighted one |
| The result count | A visually hidden live region (aria-live="polite") announcing "12 results" as results change |
| The modal | role="dialog", aria-modal="true", labeled by the visible heading or input placeholder |
Focus management
Opening the modal moves focus to the input. Closing it returns focus to whatever triggered the open — the hotkey, or the element that was clicked. Focus never silently lands on <body>.
Announcements
- A results update announces the new count, not every individual result — so typing does not flood a screen reader with a result-by-result readout.
- The zero-result state announces the same "no results" text a sighted user sees, plus its suggestions.
- A typo correction announcement follows the visible "Showing results for X" text (see Typo tolerance).
Color and motion
Nothing in the widget relies on color alone — see Status below for the indexing indicator's non-color fallback. The "indexing" pulsing ring (used in the dashboard, not the widget itself) switches to a static ring under prefers-reduced-motion: reduce.
Status indicators
Any live status shown alongside search results (for example, a degraded-mode notice) pairs a dot or icon with text — never a color shift alone — so the state reads correctly without color vision or a screen.
What to test
- Keyboard-only: open, type, arrow through results, open one, and close, without ever touching a pointer.
- A screen reader pass (VoiceOver or NVDA) confirms the announcements above.
axeruns clean against every widget state as part of CI — a widget change that introduces a new state should add anaxecheck for it.