Skip to content

[FEATURE]: announce the active turn status to screen readers in the web UI #57512

Open

Description

@pranam-s

Describe the enhancement you want to request

  • I have verified this feature I'm about to request hasn't been suggested before.

When the web UI is streaming an assistant response, a screen reader hears "Working" and then nothing. The streamed text, reasoning and tool steps are not announced while the turn runs. I use NVDA on Windows, so this is what it looks like in practice: the turn starts, "Working" is announced once, and then the transcript is silent until the turn ends, at which point the text becomes readable if I go looking for it.

Three separate things cause this:

  1. packages/session-ui/src/timeline/session-timeline-row.tsx:905 puts aria-hidden on the assistant content of the active turn, so it is not in the accessibility tree at all. That is tracked in bug(session-ui): V2 still hides streaming assistant content from screen readers #54652, with a fix open in fix(session-ui): expose streaming assistant steps #51084.

  2. There is no live region in the transcript. The only role="status" is the "Working" chip at packages/app/src/session/timeline/message-timeline.tsx:411, and it cannot announce either. It sits inside a <Show>, so the region is created along with its text, and the text is in aria-hidden spans from TextShimmer, which leaves the live region with empty text. It is also the only thing I hear, which is why "Working" is the entire experience.

  3. That chip is rendered either as the timeline's bottom spacer or as a row inside the virtualized list, so it gets re-created as the turn progresses and can be unmounted by the virtualizer.

What I would like is one polite live region, mounted with the session and outside the virtualized rows, that announces the turn status as it changes: "Thinking", "Running commands", "Searching the codebase", "Making edits", "Delegating work", and so on.

The ui.sessionTurn.status.* strings in packages/ui/src/i18n/en.ts already cover most of these and are already translated in every locale, but only ui.sessionTurn.status.thinking is used anywhere.

I would keep this to the status rather than the text itself. The guidance in packages/session-ui/src/storybook/current-session-fixtures.ts:789 says to use a status role for concise progress updates and to avoid putting the complete streaming transcript in one live region.

Activity

  1. opencode-agent commented on Oct 20, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up, @pranam-s! You're asking for a single polite live region in the web UI. It would be mounted with the session, outside the virtualized timeline rows, and announce the active turn's status as it changes ("Thinking", "Running commands", "Making edits", and so on). It would reuse the existing, already-translated ui.sessionTurn.status.* strings and announce only the status, not the streamed text.

    I checked the points you raised against dev, and they match. The only transcript status region is the "Working" chip in message-timeline.tsx. It is created inside a <Show> together with its content, that content comes from TextShimmer, and nothing outside the translation files uses the ui.sessionTurn.status.* strings yet. The maintainers will consider this.

    Related:

  2. pranam-s commented on Oct 21, 2026

    @pranam-s
    Author

    I have a draft implementation at #57520 for anyone who wants to try it. I am holding it as a draft because it changes user-visible wording and adds a live region, and I would rather have a maintainer's call on the two questions below first.

    1. The wording. The phase names come from the existing ui.sessionTurn.status.* strings in packages/ui/src/i18n/en.ts ("Thinking", "Running commands", "Searching the codebase", "Making edits", "Delegating work", "Searching the web", "Exploring"), which are already translated in every locale. Two new ones are needed: "Responding" while the answer is streaming, and "Waiting for your response" when a question or permission is pending.

    2. The set of phases. A tool call is announced by its kind, a read is "Exploring", and the fallback reuses the existing "Working" wording. Should a tool that has moved to the background keep announcing, or should the status go quiet once work is in the background?

    One thing I deliberately did not do: announce the transcript itself. The guidance in packages/session-ui/src/storybook/current-session-fixtures.ts:789 says to use a status role for concise progress updates and to avoid putting the complete streaming transcript in one live region.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions