You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(session-ui): V2 still hides streaming assistant content from screen readers #54652
V2 still hides visible assistant text, reasoning and tool steps from the accessibility tree while the active response is generating. Screen-reader users cannot browse this content until the response finishes.
The current renderer wraps assistant rows in aria-hidden={workingTurn(current().userMessageID)}. workingTurn is true for the active message while session status is not idle: condition, assistant wrapper.
OpenCode version
2.0.26 source build, latest v2 commit 4617210822bdbb31e5749751afbfb4584ccedac8 (audited 2026-10-12). The affected file is also unchanged at current dev commit 707de5832656e89cc0f04436aa1cd5f4f91c5763.
Steps to reproduce
Open a Desktop/Web session with a screen reader.
Submit a prompt that produces streamed text and tool calls.
Browse the visible assistant output before generation completes.
Expected: visible content remains available to assistive technology during generation. Actual: the entire assistant subtree is excluded by aria-hidden.
Related reports and fix
This is the V2 continuation of #33137 and #46396, and Problem 1 of #41408. They were closed by the V1 migration triage, not by a merged fix.
Existing PR #51084 removes this barrier and includes an incomplete-response accessibility regression covering text and a tool step. Earlier PR #48597 was closed in favor of #51084. The AnimatedNumber problem from #41408 is tracked separately in #54653; this issue tracks streaming-content exposure.
Thanks for the detailed report. I was able to reproduce this, and it still happens on the latest dev (707de58).
I used the app's Playwright e2e setup to show a session with an unfinished assistant message: a completed shell step plus some text. The session status is busy.
While the response is unfinished: both session-turn-assistant-content wrappers have aria-hidden="true". The text is visible on screen, but it is missing from the accessibility tree (getByRole("paragraph") finds nothing).
Once the response is finished:aria-hidden is false and the content is exposed as expected.
The script below reproduces it. Related history: #33137, #46396 and #41408 (Problem 1) were closed without a merged fix, and open PR #51084 addresses this.
Reproduction script (issue-54652.spec.ts)
// Reproduction for anomalyco/opencode#54652: streaming assistant content is aria-hidden.// Run from packages/app: bunx playwright test e2e/reproduction/issue-54652.spec.tsimport{expect,test}from"@playwright/test"import{assistantMessage,setupTimeline,shell,textPart,userMessage}from"../utils/timeline"consttext="Streaming assistant output"for(constcompletedof[false,true]){test(`assistant content accessibility (completed=${completed})`,async({ page })=>{awaitsetupTimeline(page,{messages: [userMessage(),assistantMessage([shell("prt_a11y_shell","completed","done"),textPart("prt_a11y_text",text)],{
completed,}),],})constassistant=page.locator('[data-slot="session-turn-assistant-content"]').filter({hasText: text})awaitexpect(assistant).toBeVisible()consthidden=awaitpage.locator('[data-slot="session-turn-assistant-content"]').evaluateAll((els)=>els.map((e)=>e.getAttribute("aria-hidden")))console.log(`completed=${completed} aria-hidden values:`,JSON.stringify(hidden))awaitpage.screenshot({path: `/workspace/repro/issue-54652-completed-${completed}.png`})// Visible text must be exposed in the accessibility tree.awaitexpect(page.getByRole("paragraph").filter({hasText: text})).toHaveCount(1,{timeout: 3000})})}
I'm a screen reader user on the web UI (NVDA on Windows) and hit this.
Removing aria-hidden puts the content in the accessibility tree, but it stays silent. 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 that one cannot announce either:
it sits inside a <Show>, so the region is created along with its text
the text is in aria-hidden spans (TextShimmer), and Chrome ignores aria-label on a role=generic span, so the live region computes to empty text
I don't want to open a second PR for the aria-hidden part, @aimansour has one open in #51084. What I would like to add is one polite live region outside the virtualized rows that announces the turn status ("Thinking", "Running commands", and so on). The ui.sessionTurn.status.* strings in packages/ui/src/i18n/en.ts are already translated in every locale, but only one of the twelve is used anywhere.
Would you want this tracked here, or in a separate issue?
Activity
opencode-agent commentedon Oct 12, 2026
Thanks for the detailed report. I was able to reproduce this, and it still happens on the latest
dev(707de58).I used the app's Playwright e2e setup to show a session with an unfinished assistant message: a completed shell step plus some text. The session status is busy.
session-turn-assistant-contentwrappers havearia-hidden="true". The text is visible on screen, but it is missing from the accessibility tree (getByRole("paragraph")finds nothing).aria-hiddenisfalseand the content is exposed as expected.aria-hidden={workingTurn(...)}fromsession-timeline-row.tsxmakes both cases pass. That is the same change as in fix(session-ui): expose streaming assistant steps #51084.The script below reproduces it. Related history: #33137, #46396 and #41408 (Problem 1) were closed without a merged fix, and open PR #51084 addresses this.
Reproduction script (issue-54652.spec.ts)
Run it:
bun issue-54652.spec.tspranam-s commentedon Oct 20, 2026
I'm a screen reader user on the web UI (NVDA on Windows) and hit this.
Removing
aria-hiddenputs the content in the accessibility tree, but it stays silent. There is no live region in the transcript. The onlyrole="status"is the "Working" chip atpackages/app/src/session/timeline/message-timeline.tsx:411, and that one cannot announce either:<Show>, so the region is created along with its textaria-hiddenspans (TextShimmer), and Chrome ignoresaria-labelon arole=genericspan, so the live region computes to empty textI don't want to open a second PR for the
aria-hiddenpart, @aimansour has one open in #51084. What I would like to add is one polite live region outside the virtualized rows that announces the turn status ("Thinking", "Running commands", and so on). Theui.sessionTurn.status.*strings inpackages/ui/src/i18n/en.tsare already translated in every locale, but only one of the twelve is used anywhere.Would you want this tracked here, or in a separate issue?