Custom applications
Connect a custom app by reporting its response, tool, and interaction events directly to generative-a11y.
Install core and browser delivery
npm install @generative-a11y/core @generative-a11y/domUse this path when your app owns the callbacks that confirm response, tool, or interaction events.
Keep translation thin
Connect browser delivery
Create one runtime for the mounted chat surface and keep it alive across responses.
import { createRuntime } from "@generative-a11y/core";
import { bindRuntime } from "@generative-a11y/dom";
export function createAccessibility() {
const runtime = createRuntime({});
const delivery = bindRuntime(runtime);
return {
runtime,
dispose() {
delivery.dispose();
runtime.dispose();
},
};
}Report events at the source
Call the factory when your surface mounts, then dispatch from the transport or application callbacks that confirm each event. This sequence shows a successful response; replace the sample ID and text with your app's values, and send only newly added text in each delta.
import { createAccessibility } from "./accessibility";
const accessibility = createAccessibility();
const { runtime } = accessibility;
runtime.dispatch({ type: "response.started", responseId: "response-1" });
runtime.dispatch({
type: "response.text.delta",
responseId: "response-1",
delta: "A complete sentence.",
});
runtime.dispatch({ type: "response.completed", responseId: "response-1" });Dispose by ownership
Stop your transport subscriptions, then call this when the chat surface unmounts. Do not dispose after each response: delivery may still have paced output queued.
accessibility.dispose();Report interruption and failure
Send exactly the terminal event confirmed by your app. For a cancelled response,
use this instead of response.completed:
runtime.dispatch({ type: "response.interrupted", responseId: "response-1" });For a failed response:
runtime.dispatch({ type: "response.failed", responseId: "response-1" });Preserve stable IDs
Use response and tool IDs from your app, with a namespace when multiple surfaces share a runtime. Labels, array positions, and render counts are not stable IDs. Provide translated user-facing labels when reporting tools or interactions. See the event reference for their required fields.
Compatibility and delivery
The packages require Node.js 22+ and have no framework peers. Core works without
a browser; DOM delivery stays inactive when document is unavailable. In React,
use A11yProvider to own runtime and browser delivery instead of
calling the factory above.
Your app keeps its visible UI, semantic structure, keyboard controls, and focus management. Ordinary streaming does not move focus. Browser delivery tests do not establish what a screen reader speaks.
Leave out events the framework cannot report
Do not treat streamed arguments as a completed tool, a repeated render as a retry, a ready state as an interruption, or a tool name as an approval. If the framework does not report an event, the adapter leaves it out.