Accessibility

The accessibility features the primitives provide, and what your application still has to supply.

The primitives handle ARIA attributes, roles, keyboard navigation, and focus management. Because the package renders no styles, anything visual — contrast, focus indication — is your application's responsibility.

Keyboard navigation

The primitives follow the WAI-ARIA Authoring Practices. The composer's editor interprets keys by mode: an open command list, or an active ask-user flow, takes priority over normal typing. Each primitive page documents its own key table.

Command lists and ask-user options move a highlight rather than DOM focus, so the caret stays in the editor while you navigate. Arrowing past the end of a list keeps focus in place; arrowing up past the first ask-user option returns to the editor.

Focus management

Focus is managed automatically after interaction — the composer restores the caret after selecting a command item, and ask-user recovers arrow navigation if a click elsewhere drops focus to the body.

In command lists and ask-user options the highlight is the focus indication — focus follows it rather than moving separately, so styling the highlight faintly removes the focus indicator rather than softening a hover effect.

Roles and relationships

The composer's editor is wired to its command list as a combobox: aria-expanded, aria-controls, and aria-activedescendant reference a listbox, and the active row carries aria-selected. Ask-user renders a labelled radiogroup, or checkboxes with aria-checked for multi-select questions. Disabled options are announced but skipped by highlight and selection.

Steps marks the active item with aria-current="step". Reasoning.Root carries aria-busy while streaming.

Accessible labels

Interactive parts carry default accessible names; containers do not, since they are not controls. Composer.Submit announces as "Stop generating" while generating rather than "Send message". Attachments.Remove takes a filename so each remove button announces its own item.

All defaults are overridable via aria-label or aria-labelledby. Anything announced as content rather than as a name — status text, validation messages — is text you render, so it is localised wherever your copy lives.

Testing

The package runs an axe-based suite over the composer combobox wiring, the ask-user flows, the display primitives' status attributes, and accessible names across controls. Automated checks can't evaluate contrast or focus visibility in your styling, so those need your own pass.