Labeling, keyboard behavior, focus management, and live-region support in the Liquid Glass components.
Accessibility is built into the behavior layer, not the glass styling. The interactive components provide roles, states, keyboard interaction, focus management, and native form integration. The visual layer only changes the surface.
This guide describes the guarantees you can rely on and the decisions you still need to make in your application.
| Component | Accessible name source |
|---|---|
Input | Field label, or aria-label / aria-labelledby |
Checkbox | label, or aria-label / aria-labelledby |
CheckboxGroup | label, or aria-label / aria-labelledby; each item has its own label |
Switch | label, or aria-label / aria-labelledby |
RadioGroup | label, or aria-label / aria-labelledby |
Select | label, or aria-label / aria-labelledby |
Slider | aria-label / aria-labelledby, or getAriaLabel per thumb |
Progress | label, or aria-label / aria-labelledby |
Tabs | aria-label / aria-labelledby on the tab list |
Toggle | label, or aria-label / aria-labelledby |
ToggleGroup | aria-label / aria-labelledby |
ScrollArea | aria-label / aria-labelledby on the viewport |
Menu | Trigger label, or aria-label / aria-labelledby for icon-only triggers |
Tooltip | Trigger label; the tooltip content is supplementary |
Dialog, AlertDialog, Drawer | Required title prop |
Popover | Required title prop |
Fieldset gives a group of related fields a shared accessible name from its
legend; the controls inside still need their own labels.
Visible labels are preferred. A label rendered outside the component is fine as long as it is associated correctly:
<span id="volume-label" className="text-sm text-ui-ink">
Volume
</span>
<Slider aria-labelledby="volume-label" defaultValue={40} />For a range slider, pass getAriaLabel so each thumb gets a distinct name:
<Slider
aria-label="Price range"
defaultValue={[20, 80]}
getAriaLabel={(index) => (index === 0 ? "Minimum price" : "Maximum price")}
/>Switch and Checkbox use the visible label as the accessible name and link
the description through aria-describedby. CheckboxGroup names the group and
each option separately, and Tab moves between its checkboxes. Decorative icons inside Button,
Input, and other components are marked aria-hidden="true".
The components follow these native interaction patterns:
| Interaction | Expected behavior |
|---|---|
Tab / Shift+Tab | Move focus between controls |
Enter / Space | Activate buttons, toggles, checkboxes, switches, tabs, menu items, and select options |
| Arrow keys | Move slider thumbs, navigate toggle groups and tabs, and move through menu items or select options |
Escape | Close a dialog, alert dialog, drawer, popover, menu, select, or tooltip |
Home / End | Move a single-value slider to its bounds (range thumbs move to the adjacent thumb boundary), or jump to the first or last tab |
Page Up / Page Down | Move a slider by largeStep |
| Typeahead | Match labels in a menu or select |
Accordion triggers use real buttons and expose aria-expanded; they follow the
document tab order. loopFocus and orientation are deprecated and no longer
change keyboard focus. Toggle groups support single and multiple selection with
the expected arrow-key roving focus. Tabs use roving focus inside the tab list:
arrow keys follow the orientation, Home and End jump to the ends, and
Enter or Space activates the focused tab. Set activateOnFocus to switch
panels as focus moves. Scroll areas keep native wheel, trackpad, and keyboard
scrolling; the custom scrollbars are decorative and hidden from assistive
technology.
Menu and Select use roving focus inside their popups: arrow keys move
through enabled items, typeahead matches labels, and Escape returns focus to
the trigger. Disabled items stay announced
but cannot be activated. Tooltip opens on hover or keyboard focus and closes
on blur or Escape; it is visual-only and not announced as a description, so
icon-only triggers still need their own accessible name.
Dialog, AlertDialog, and Drawer are modal:
Tab stays inside the popup while it is open.Escape closes all three overlays. Backdrop dismissal also closes Dialog and Drawer unless disabled; AlertDialog always blocks it.Popover is deliberately non-modal: focus is not trapped, the page stays
scrollable, and outside press or Escape closes it. Use it for compact
settings, filters, and contextual actions, not for multi-step flows that need
the user's full attention.
Menu and Select are modal by default: outside interaction is locked while
their popup is open, and Escape closes the popup and returns focus to the
trigger. Set modal={false} only when the surrounding page must stay
interactive.
AlertDialog is for destructive or irreversible decisions. Use it instead of a
plain Dialog when the user must choose between explicit actions.
ToastProvider renders a toast viewport with live-region semantics.
Keep one provider near the application root, and render <Toast /> after the
app content so the viewport is available.
type to add a status icon: info, success, warning, error, or
loading.priority: "high" for an assertive announcement, such as a failed save.actionProps when the user can undo or retry.timeout long enough to read the message, or set timeout: 0 when the
toast requires action.toast.promise starts with a loading state and updates the same toast when the
promise settles, which avoids announcing duplicate messages.
All decorative transitions include motion-reduce variants. When the user sets
prefers-reduced-motion: reduce, the layout and state changes remain but the
motion is removed or shortened.
The glass surface is translucent. Check text contrast against the actual
background, especially over images, gradients, and busy dashboards. The optional
glass preset plugin provides
data-glass="thick" for a stronger shared veil without changing component
code. The default monochrome palette is designed for a quiet
interface; custom tokens should keep the same contrast relationship in both
themes.
Switch and Checkbox announce their checked state.CheckboxGroup announces its name and each option once.Menu and a Select with the keyboard and confirm arrow keys,
typeahead, and Escape behave as expected.Tooltip trigger and confirm its accessible name.Accessibility is a shared responsibility. The components provide the interaction foundation, but the surrounding headings, error messages, page structure, and content still belong to your application.