Customize
Accessibility
This page states exactly what each interactive component does today, including where it falls short, so you can decide what to add for your own product.
Approach
- Use the platform. Checkbox, Radio, Select, Slider and the text fields are real
<input>/<select>elements, so forms, autofill, labels and assistive tech work without custom code. - Real roles on the rest. Custom widgets carry the ARIA roles and states that apply, and are reachable by keyboard.
- Visible focus. A 2px accent outline everywhere, a 3px ring on fields.
- Reduced motion. One global rule; see Motion.
Keyboard and semantics
| Component | Semantics | Keyboard |
|---|---|---|
| Button, Toggle, Chip | Native <button>; Toggle uses aria-pressed; loading sets aria-busy | Enter / Space |
| Checkbox, Radio | Native inputs, grouped by name | Space; arrow keys inside a radio group |
| Switch | role=switch with aria-checked | Enter / Space |
| Slider | Native range input | Arrow keys, Home / End, PageUp / PageDown |
| Select | Native <select> | Native behavior |
| OtpField | One labelled input per digit; autocomplete=one-time-code | Auto-advance, Backspace goes back, ← →, paste fills all |
| Dialog | role=dialog, aria-modal, aria-labelledby | Esc closes; Tab and Shift+Tab are trapped; focus returns to the trigger |
| Sheet | role=dialog, aria-modal, aria-labelledby | Esc closes; focus moves into the panel |
| Popover | Trigger sets aria-expanded | Esc or outside click closes |
| DropdownMenu | role=menu, menuitem; trigger aria-haspopup | ↑ ↓ wrap; first item focused on open; Esc closes |
| Command | Input role=combobox with listbox / option items | ↑ ↓ move, Enter runs, typing filters |
| Tabs | tablist / tab / tabpanel with aria-controls; roving tabindex | ← → move and activate |
| Accordion | Button with aria-expanded / aria-controls; region panels | Enter / Space |
| Tooltip | role=tooltip with aria-describedby | Shown on hover and on focus within |
| Toast | Region aria-live=polite; each toast role=status | Dismiss is a button; hover pauses the timer |
| Breadcrumb, Pagination | nav with aria-label; aria-current on the current item | Native links and buttons |
| Stepper | Ordered list; aria-current=step | Not interactive |
| Progress, Meter | role=progressbar / role=meter with aria-value* | Not interactive |
| Calendar | Day buttons with aria-pressed and aria-current=date | Tab through days |
| RotatingCarousel | role=group, aria-roledescription=carousel | ← → on the focused carousel; dots and buttons are focusable |
| SplitShowcase | role=slider with aria-value* | ← → adjust the divider |
| Skeleton, Spinner | Skeleton is aria-hidden; Spinner has role=status and a label | — |
Known gaps
Listed plainly, so you can plan for them:
- Sheet and Popover do not trap focus. Dialog does. If a Sheet holds a form, consider rendering it inside a Dialog or adding the same Tab handling.
- DropdownMenu does not return focus to its trigger on close, and has no type-ahead.
- Command highlights the active row visually but does not set
aria-activedescendant. - Segmented and Rating expose radio roles on buttons but do not implement arrow-key navigation between options; each is a Tab stop.
- Tabs do not handle Home and End.
- Calendar is a button grid without grid arrow-key navigation.
- Decorative effects (Marquee, Typewriter, Scramble, Orbit and similar) animate indefinitely and do not offer a pause control. Avoid them for essential content, and note that reduced motion shortens but does not remove their text.
Fixes are welcome: see Contributing, or open an issue on GitHub.
Color and contrast
- Body text uses
ink-softandmutedonsurfaceorcanvas.faintis for placeholders and decoration and is intentionally low contrast. - Never rely on color alone: status pills and alerts always include text, and alerts include an icon.
- If you retint the accent, keep a 4.5:1 ratio between
--accentand--accent-ink.
Testing your screens
- Tab through the whole page without a mouse. Every control should be reachable and visibly focused.
- Turn on reduced motion in your OS and reload. Nothing should depend on an animation to be understood.
- Run a screen reader on a form and an overlay. Labels, roles and names should be announced sensibly.
- Check both themes. Contrast problems often appear in only one.