Blog · · 11 min read

AI agent accessibility for streaming, approvals, and recovery

AI agent accessibility for streaming, approvals, and recovery

AI agent accessibility can fail even when the surrounding page passes an audit. A screen reader may miss tool-mode state, announce every streamed token, or lose the result after an approval dialog closes. Keyboard users may reach controls hidden with an off-screen chat panel. Labels on the prompt box cannot cover these failures. The product needs one accessibility contract over the durable agent run, from queued work through progress, input requests, approval, cancellation, failure, and recovery. This guide maps those states to programmatic status, keyboard actions, focus behavior, timing rules, and an assistive-technology test matrix.

Build the accessibility contract over the run

The chat transcript is one view of a product workflow. The same durable run record that drives progress, approval, and recovery should also drive accessibility state. The interface can then restore a stable answer after a refresh, reconnect, or handoff.

Build it in this order:

  1. Define a small run-state machine and the commands permitted in each state.
  2. Assign every state a visible label, programmatic status, focus policy, and keyboard-reachable action set.
  3. Separate visual token streaming from assistive announcements.
  4. Represent tool modes and expanded panels with native control semantics and explicit state.
  5. Bind each approval dialog to one durable request and a documented timing policy.
  6. Keep failure, cancellation, and recovery states available after the transient chat update ends.
  7. Test real state transitions with keyboards, screen readers, zoom, contrast modes, and reduced motion.

WCAG 2.2 is the normative baseline. The contract is the product architecture that applies that baseline to agent behavior. A widget checklist covers message input and output. The run contract must also cover every state of action-taking work.

Why page-level checks miss agent failures

Agent interfaces create several timing and state problems that ordinary forms do not:

  • The visible answer changes token by token, but a screen reader needs useful semantic updates.
  • A tool or mode can become active without a new page or obvious text change.
  • Work may continue after the browser disconnects.
  • The next required action can move from the prompt to a progress card, approval dialog, or recovery panel.
  • A timeout can expire while someone is reading the proposed effect.
  • Cancellation may be requested before the backend knows whether an in-flight effect committed.

W3C's guidance for status messages explains that important content changes must be programmatically available without taking focus. That applies directly to queued, working, blocked, completed, and failed run states. It does not mean every token belongs in a live region.

Two issue reports show how narrow UI choices create larger failures. An Open WebUI screen-reader report describes tool controls that exposed neither their purpose nor selected state. A separate Open WebUI repair record covers nested controls, popup state, hidden focusable content, skip targets, and keyboard navigation. These are author and maintainer reports, not prevalence statistics. They provide concrete failure cases for regression tests.

Map every durable state to accessible behavior

Draft the state table before changing components. The exact state names can differ, but each row needs one durable meaning.

Run stateProgrammatic statusFocus and keyboard ruleAvailable action
queuedAnnounce that work was accepted and why it is waitingKeep focus on the initiating surfaceCancel when policy allows
workingAnnounce phase changes, not every token or eventDo not move focus for background progressPause or cancel when supported
input_requiredIdentify the missing field and affected stepMove focus only after a user action opens the requestSupply input or hand off
approval_requiredName the proposed effect, target, and expiryPut focus in the opened dialog and contain it thereApprove, reject, or modify
completedAnnounce the verified outcome onceKeep or return focus to a stable run summaryInspect receipt or start another task
failedAnnounce the failed step, known effects, and ownerFocus the error summary only when the user's action caused the transitionRetry safe work, recover, or hand off
cancelledDistinguish stopped future work from committed effectsReturn focus to the run summary or triggerInspect effects or compensate
recoveredAnnounce what changed and what remains unresolvedPreserve a stable path to the original failureClose or continue under a new action version

Do not derive this table from model prose. Project it from product and orchestration events. The visible sentence can change, but the underlying state and available commands must remain stable.

Store the accessibility behavior alongside the run view instead of scattering it across components:

type RunA11yState = {
  runId: string;
  status:
    | "queued"
    | "working"
    | "input_required"
    | "approval_required"
    | "completed"
    | "failed"
    | "cancelled"
    | "recovered";
  statusSummary: string;
  announcementKey: string;
  announcementPriority: "polite" | "assertive" | "none";
  focusTargetId?: string;
  availableCommands: Array<"pause" | "cancel" | "approve" | "reject" | "modify" | "retry" | "handoff">;
  actionVersion: number;
  updatedAt: string;
};

announcementKey should identify a semantic transition such as run-42:working:validation-complete, not a rendered token count. The client can suppress duplicate keys after reconnecting while still rendering the current status.

Implement AI agent accessibility for streaming output

Use separate channels for sighted users and assistive technology:

  1. A visual stream can update frequently for sighted users who choose to watch generation.
  2. An assistive summary channel announces meaningful boundaries, such as a completed sentence, a named phase change, a request for input, or a terminal result.

A current streaming and screen-reader implementation article discusses throttling, sentence-level announcements, and testing with assistive technology. Those are implementation options to test against your own content and users. One batching interval will not work for every screen reader or workflow.

For the stream:

  • Do not wrap the entire token stream in an assertive live region.
  • Do not replace the live-region node on every update. Keep one stable announcer and update its text at semantic boundaries.
  • Let users pause visual streaming or choose a reduced-update presentation when your interface supports continuous motion.
  • Keep the final response in ordinary document structure so it remains navigable after streaming ends.
  • Announce product state separately from generated content. "Waiting for approval" is not part of the model answer.
  • Cancel queued announcements when a newer state makes them false.

The chatbot accessibility guide from Make Things Accessible covers focus, labels, announcements, rich media, contrast, overload, and timeout concerns. An agent interface needs those foundations plus durable task state and action controls.

Make tool modes and hidden panels operable

Start with native buttons, inputs, dialogs, lists, and headings. An icon-only tool toggle needs an accessible name and a programmatic selected or pressed state. If it opens a popup, expose whether the popup is open and connect the control to the owned content.

Do not hide a panel by moving it off-screen while leaving its descendants in the tab order. A CopilotKit repair addressed a closed agent chat that remained exposed to keyboard and assistive-technology navigation until the hidden panel was made inert. Turn that bug into a regression case: close the panel, press Tab through the surrounding page, and inspect the accessibility tree.

Do not communicate tool state through color and icon shape alone. For example, a web-search button can expose "Web search, on" through a pressed state while the visible icon remains compact. If selecting a tool changes the data the agent may send, put that consequence in nearby text or a disclosure that keyboard users can reach.

Microsoft's accessibility and inclusion guidance for agents recommends user control, multiple interaction methods, descriptive alternatives, logical focus order, sufficient timing, error recovery, and testing with people with disabilities. Use that guidance as a design baseline, then enforce the behavior in component and end-to-end tests.

Make approval focus and timing explicit

An approval is a workflow state, not a generic confirmation. The accessible name should identify the proposed action. The description should include the target, material parameters, consequences, reversibility, and expiry.

Persist and open approvals in this order:

  1. Persist the approval request with its action version before opening the dialog.
  2. Open the dialog in response to a known state transition.
  3. Move focus to a suitable element inside it, based on the content and risk.
  4. Keep Tab and Shift+Tab inside while the modal remains active.
  5. Offer approve, reject, and modify actions as named controls.
  6. On close, return focus to the invoking control or the stable run summary when the original control no longer exists.
  7. If the action changed, expire the old request instead of reusing its decision.

The WAI-ARIA modal dialog pattern documents keyboard interaction, accessible naming, focus containment, initial focus choices, and focus return. Copy the documented behavior, rather than adding role="dialog" to an overlay that lacks the required keyboard and focus handling.

Approval expiry also needs an accessibility policy. W3C's Timing Adjustable guidance requires users to turn off, adjust, or extend content-imposed limits unless a documented exception applies. Warn before expiry, make the remaining time available programmatically, and preserve the proposed action if the request expires. An expired approval should return to a recoverable state instead of discarding the work and forcing the user to reconstruct it.

Keep cancellation, errors, and recovery understandable

For a failed run, persist:

  • the user's original goal;
  • the current run and action version;
  • completed, failed, skipped, and unknown effects;
  • the control that caused the transition;
  • the next safe actions;
  • the current recovery owner.

Use assertive announcements sparingly for conditions that require immediate attention, such as a destructive approval becoming invalid while its dialog is open. Routine progress can remain polite. A failure that appears after background work should remain in the durable run summary until someone resolves it.

Separate cancel requested from cancelled. If a side effect is in flight, show that the stop request is pending. Once the backend reconciles the effect, announce whether it committed and expose compensation or handoff when needed. This prevents the accessibility layer from claiming safety before the product has established the outcome.

When recovery opens another modal or route, maintain a return path to the original run. Do not rely on browser history alone. Store the run ID and intended focus target so a reload can reconstruct the same context.

Verify the contract across assistive technology and run state

Automated scans can catch missing names, invalid nesting, contrast defects, and some focus problems. They cannot prove that streaming cadence is usable or that a recovery flow makes sense. Pair automation with manual state-transition tests.

Test these combinations:

  • Keyboard only, including reverse tab order and shortcut conflicts.
  • At least one screen reader and browser combination supported by your product team.
  • 200% and 400% zoom with reflow.
  • High-contrast or forced-colors mode.
  • Reduced-motion preference.
  • Speech input or another non-pointer input method where relevant.
  • Slow reading and interaction across approval timeouts.
  • Browser disconnect and reload during every nonterminal run state.

Run each combination through these cases:

  1. Start a run with and without a tool mode enabled.
  2. Stream a long response while product progress changes in parallel.
  3. Request missing input after several completed steps.
  4. Open, modify, reject, and expire an approval.
  5. Close and reopen the agent panel.
  6. Request cancellation during an in-flight effect.
  7. Force partial failure, retry, compensation, and handoff.
  8. Reload and require the same state, controls, focus destination, and summary.

The assertions should cover the accessible name, role, state, announcement, focus target, and keyboard actions for each transition. Include duplicate-event and reconnect tests so the announcer does not repeat stale progress.

Common implementation mistakes

A single global live region mixes generated text with product status and makes announcement order unpredictable.

Moving focus for every progress update interrupts reading. Announce status without moving focus unless the user opened a new interaction surface or an urgent error requires action.

Adding ARIA to a custom clickable element does not recreate all native button behavior. Use the native control when possible.

Closing a panel visually while leaving it focusable creates a hidden keyboard route. Verify both the tab order and accessibility tree.

An approval timeout with no extension or recovery path can erase work before a user finishes reviewing it.

Running only an automated scanner misses streaming cadence, recovery comprehension, and cross-state focus continuity.

What to do next

Choose one action-taking workflow and add accessibility columns to its durable state table: programmatic status, announcement boundary, focus target, keyboard commands, timing rule, and recovery path. Then run the eight transition cases above with a keyboard and your supported screen-reader combination. AI agent accessibility is ready to ship only when a reload, expired approval, partial failure, and cancellation preserve the same understandable run state as the normal path.

References

Be first in line.

Join the waitlist and we'll email you the moment it's ready. No sales call.

Try the demo →
or talk to us