Integrations

Vercel AI SDK accessibility

Add paced screen-reader updates to AI SDK 7 and @ai-sdk/react 4 through documented state, finish callbacks, and error callbacks.

Install the AI SDK adapter

Install @generative-a11y/core, @generative-a11y/dom, and @generative-a11y/ai-sdk beside the AI SDK packages already used by your application. The adapter translates public chat state and callbacks; it does not replace useChat or render a chat interface.

  • Use the React subpath when your application connects through @ai-sdk/react.
  • Create one accessibility runtime for the chat surface and dispose it when that surface unmounts.

React integration

Create the accessibility integration before useChat so composed callbacks are present at construction, then observe its documented snapshot after useChat runs.

tsx
import { useChat } from "@ai-sdk/react";
import {
  useChatAccessibility,
  useObserveChatAccessibility,
} from "@generative-a11y/ai-sdk/react";

const accessibility = useChatAccessibility({
  runtime,
  scopeId: "support-thread",
  onFinish: hostOnFinish,
  onError: hostOnError,
});
const chat = useChat({ id: "support-thread", ...accessibility.chatCallbacks });
useObserveChatAccessibility({ integration: accessibility, snapshot: chat });

How this code works

  1. 01
    Create accessibility first

    The hook creates one observer and composed callbacks before useChat captures its initial options.

  2. 02
    Keep your callbacks

    The integration observes onFinish and onError, then calls the callbacks supplied by your app.

  3. 03
    Construct useChat

    Spreading chatCallbacks tells the adapter when a response completes, stops, or fails.

  4. 04
    Observe public state

    The second hook reads only messages, status, and error from the returned useChat helpers.

Options and return values

runtimePick<GenerativeA11yRuntime, 'dispatch'>Required

Receives events from the integration. Your app owns this runtime, so the integration never disposes it.

Default
none
scopeIdstringRequired

A stable non-empty namespace for message, tool, approval, and source IDs in this chat instance.

Default
none
maxTrackedEntitiesnumberOptional

Bounds each identity collection. Invalid values throw and saturation suppresses later unknown identities.

Default
1000
getToolLabel(context) => stringOptional

Maps public tool identity to short localized copy. It must not expose arguments or raw results.

Default
"A tool"
onFinishChatOnFinishCallbackOptional

Your existing finish callback. It is composed rather than replaced.

Default
undefined
onErrorChatOnErrorCallbackOptional

Your existing error callback. Raw errors are not copied into announcements.

Default
undefined
chatCallbacks{ onFinish, onError }Return

Spread these callbacks into useChat so the adapter knows exactly when a response finishes or fails.

Default
n/a
snapshotPick<UseChatHelpers, 'messages' | 'status' | 'error'>Required

The public useChat return object observed after useChat has been invoked.

Default
none

Lifecycle mapping

The observer maps documented message parts and chat status to response, text, tool, approval, and citation events. Composed callbacks confirm completion and failure. Your application must report retry actions because public AI SDK state does not identify every retry request.

  • messages and status identify active response text and known tool states
  • onFinish confirms completion or stop details
  • onError confirms failure without copying raw error text

Expected screen-reader behavior

Core groups streaming text into paced announcement intents and gives approval, failure, and completion updates suitable priority. The DOM package writes those intents to live regions without moving focus during routine status changes. Browser transcripts confirm DOM delivery; test VoiceOver, NVDA, or another target screen reader before making support claims.

What the adapter can report

Use supplied callbacks so the adapter knows when a response finishes, stops, or fails. Status alone does not provide enough detail. Report regenerate actions from your app when you need retry events. A successful response after an error tells the adapter that the connection returned.

  • Exports CHAT_ADAPTER_METADATA, createObserver, composeChatCallbacks
  • React subpath exports useChatAccessibility and useObserveChatAccessibility
  • Tool failure, approvals, and citations use stable public part IDs

Troubleshooting

Missing completion updates often mean useChat captured callbacks before the accessibility integration created them. Repeated output can indicate an unstable scopeId or more than one observer attached to the same chat. Inspect runtime diagnostics, then compare the observed public state with the lifecycle mapping above.

  • Create the integration before constructing useChat.
  • Keep scopeId stable for the lifetime of one chat instance.
  • Use the lifecycle lab to inspect deterministic browser updates before testing assistive technology.