An accessible agent interface separates a stable conversation transcript from concise status announcements and fully operable controls. It does not move focus for every tool call, announce every streamed token, require speech, or hide consequential actions behind an unlabeled activity indicator. Users need predictable focus, keyboard access, pause and cancel controls, and a clear record of what the agent did.
Build on semantic document structure
Use one <main>, a descriptive page heading, semantic regions for conversation and task activity, native buttons and form controls, and a logical heading hierarchy. Each message should expose speaker, content, and relevant status without encoding identity only through color or alignment.
<article aria-labelledby={`message-${message.id}-speaker`}>
<h3 id={`message-${message.id}-speaker`}>{message.speaker}</h3>
<div>{message.content}</div>
</article>
If every message heading makes navigation noisy, use a semantic list with visually presented speaker labels. Test alternatives with actual assistive-technology users; HTML shape should follow the interaction, not a universal chat template.
Do not announce every token
Streaming token-by-token into an aria-live region can interrupt reading and create hundreds of announcements. Render visual streaming in the transcript, but announce a concise completion or meaningful phase change through a separate status region.
The ARIA log role has implicit polite live behavior and is intended for sequential updates such as chat logs. The W3C technique notes that new log entries can be announced without rereading the entire log. See ARIA23: role=log.
<section role="log" aria-label="Conversation" aria-relevant="additions">
{messages.map(renderMessage)}
</section>
<p role="status" aria-atomic="true">{conciseStatus}</p>
Throttle status changes. “Searching documentation,” “Waiting for approval,” and “Answer complete” are meaningful; animation frames, token counts, and every retry usually are not.
Keep focus under user control
Sending a prompt should normally leave focus in or return it predictably to the composer only if that matches the user’s action. New messages should not steal focus. When opening a modal approval dialog, move focus into it, trap focus while open, support Escape or an explicit cancel control, and restore focus to the invoking element after close.
If the agent navigates to a new route or materially replaces the view, move focus to an appropriate heading and announce the context change. Do not use focus movement merely to make a screen reader speak new content.
Provide skip links or landmarks for conversation, task activity, sources, and composer. Long conversations need message-level navigation, search, or collapse controls that work without a pointer.
Make all agent actions keyboard operable
Every send, stop, retry, copy, inspect source, expand details, approve, reject, and voice control needs a native keyboard-operable element with a stable accessible name. Avoid clickable <div> elements and icon-only buttons without labels.
Keyboard shortcuts must not conflict with text entry or assistive technology. Show them, allow disabling or remapping when appropriate, and do not make a shortcut the only way to stop voice output.
Present tool progress as a state machine
Tool activity needs states users can understand:
queued → running → waiting for approval → succeeded
↘ rejected
↘ failed / canceled
Display tool name in user language, purpose, affected resource, elapsed state, and result. A spinner without text is insufficient. Keep completed activity in the transcript or an inspectable audit region rather than removing it immediately.
For long work, provide pause or cancel where technically honest. If cancellation cannot reverse a completed side effect, say so.
Design approvals for comprehension
An approval control should state:
- the exact action;
- target account, file, person, or environment;
- important values and external consequences;
- what data will be sent and to whom;
- whether the action is reversible;
- approval expiry; and
- distinct approve and cancel controls.
Do not rely on a red button to communicate danger. Put the action in the accessible name, such as “Approve deletion of project Atlas,” while avoiding unnecessarily verbose repetition.
After approval, announce whether execution started and later whether it completed. Approval is not completion.
Make voice optional and visible
Microphone use should have a clear start action, persistent recording indicator, stop control, and text alternative. The Media Capture specification defines an express browser-permission flow and privacy indicators for capture; it also emphasizes revocation and preventing stored permissions from being abused. Browser permission is a technical control, not a conclusion that every legal consent requirement has been satisfied. See Media Capture and Streams.
Show partial transcript so users can correct recognition before consequential action. Support keyboard entry, paste, and review without requiring speech. Captions for agent audio should match the spoken output and remain available after playback.
Handle errors without losing work
Associate validation errors with their fields, summarize submission errors, and preserve the user’s input. Announce a concise failure once, then provide detailed diagnostics on request. A reconnect should not clear the transcript, re-submit a prompt, or duplicate an approved action.
Differentiate “response canceled,” “connection lost,” “tool failed,” and “action outcome unknown.” The last state is important after a timeout: retrying may duplicate an external effect.
Test behavior, not only markup
Automate semantic checks and targeted ARIA snapshots, then test full flows using only keyboard, browser zoom, high contrast, reduced motion, screen readers across supported platforms, speech input where supported, and switch or alternative input as relevant. Playwright can assert accessibility-tree structure with ARIA snapshots, but those snapshots do not simulate how every assistive technology behaves. See Playwright ARIA snapshots.
Test streaming, interruption, approval, error recovery, long transcripts, citations, and reconnection—not only the initial empty composer.