Skip to content

fix(web): screen readers no longer say "Message" twice entering the composer - #26692

Open
nibarAhmed wants to merge 2 commits into
pingdotgg:mainfrom
nibarAhmed:fix/composer-double-announcement
Open

nibarAhmed wants to merge 2 commits into
pingdotgg:mainfrom
nibarAhmed:fix/composer-double-announcement

Conversation

@nibarAhmed

Copy link
Copy Markdown
Contributor

Problem

Since #25877, screen readers announce the composer twice when focus enters it. NVDA says "Message input, Message , edit, has auto complete, multi line, opens list". The F6 workspace area around the composer became a region named "Message input", and the editor inside it is already labelled Message <thread title>, so both names are read.

Fixes #26675

Change

workspaceAreaProps now takes an optional label. It only adds role="region" and aria-label when a label is given. F6 navigation keeps working because it only uses data-workspace-area, data-workspace-order and tabIndex. The composer area no longer passes a label, so the editor's own name is the only one read. The other workspace areas keep their labels, since F6 can land on those wrappers directly (for example Conversation).

Trade-off: the composer is no longer an NVDA landmark (D key). If F6 goes back to a button that was last focused in the composer, such as Send, NVDA reads only that button without saying it's in the composer. That matches how the composer was announced before #25877.

I considered keeping the region and renaming it (for example "Composer") instead. As a daily NVDA user, I find any second name read on every entry into the composer noisy, and the editor's Message <thread title> label already says where you are. Removing the region is the version that actually removes the noise.

Scope and approval

This is a very small, focused fix for an obvious regression from #25877. It changes one string and makes one argument optional across two files. It doesn't change F6 behavior, and the other workspace areas are untouched. The regression and its cause are written up in #26675.

Verification

Desktop dev build on Windows 11 with NVDA, moving focus into the composer:

  • Before (main): "Message input, Message Screen Reader Thread List Regression, edit, has auto complete, multi line, opens list"
  • After (this branch): "Message New thread, edit, has auto complete, multi line, opens list"

F6 into and out of the composer still works. vp run check:changed passes (format, lint, knip, typecheck, nearby tests).

Not checked: VoiceOver on macOS, and the hosted web app (it uses the same web code as desktop). Mobile doesn't use this code.

Made with Claude Opus 5.5 in Claude Code, running in T3 Code.

🤖 Generated with Claude Code

…omposer

The composer's F6 area was a region named "Message input", so screen readers
read it before the textbox's own "Message <thread>" label. The label is now
optional, and areas without one are not regions.

Fixes pingdotgg#26675

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Oct 28, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 16bead9

Macroscope's review found this PR approvable — Removes the redundant composer region announcement while preserving workspace focus navigation and other regions’ labels. Reported NVDA testing confirms the improvement; the limited trade-off is that the composer no longer appears as a separate landmark.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 16bead9 and 4ce2723.

Files selected for processing: 1
  • apps/web/src/components/ChatView.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Walkthrough

The workspace-area helper now accepts an optional label and adds aria-label and role="region" only when a label is supplied. The composer registers its workspace area without a label.

Changes: Composer accessibility

Layer / File(s) Summary
Optional workspace label
apps/web/src/lib/workspaceFocus.ts, apps/web/src/components/ChatView.tsx
workspaceAreaProps makes label optional and adds aria-label and role="region" only when the label is truthy. The composer calls the helper without a label.

Estimated code review effort: 2 (Simple) | ~5 minutes

Change: Bug fix · Severity of issue fixed: Low

Possibly related PRs

Suggested labels: bugfix

Suggested reviewers: t3dotgg

Merge Risk: Minimal · up to 4ce27

No concrete accessibility or keyboard-navigation regression is established; the change is mergeable.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title names the main change: the composer no longer makes screen readers announce "Message" twice. It matches the diff, which makes the label optional in workspaceAreaProps and removes the compose…
Description check Passed The description follows the template's sections: Problem, Change, Scope and approval, and Verification. The Problem section gives the regression, the NVDA output, and the linked issue #26675. The Chan…
Linked Issues check Passed The change meets the coding requirements in [#26675]. ChatView.tsx omits the composer label. workspaceFocus.ts keeps the workspace data attributes and tabIndex, and adds role="region" and `ari…
Out of Scope Changes check Passed The whole-PR diff changes only the composer call site and the optional-label behavior in workspaceFocus.ts. Both changes directly address [#26675]. The diff contains no demonstrated unrelated produc…
Full details: Title check

Explanation

The title names the main change: the composer no longer makes screen readers announce "Message" twice. It matches the diff, which makes the label optional in workspaceAreaProps and removes the composer's label. It is a conventional commit title in plain language, as the template asks.

Full details: Description check

Explanation

The description follows the template's sections: Problem, Change, Scope and approval, and Verification. The Problem section gives the regression, the NVDA output, and the linked issue #26675. The Change section explains the optional label, the composer label removal, and the F6 behavior, plus a trade-off. Scope and approval cites a very small, focused fix and links the regression and its cause in #26675. The author links the issue, but the template asks for a triaged issue or maintainer approval, and the issue link alone does not show that approval. Verification gives before and after NVDA output on Windows 11, F6 checks, and the check command. It states what was not checked. The description does not include a screenshot or recording, though the template asks for before and after screenshots for UI changes. The NVDA before and after text is a textual substitute, not a visual. The template also asks for the model and harness, and the description includes this line. The description is mostly complete, so the check passes. The gaps are the missing screenshot or recording, and the scope note that rests on the linked issue rather than on explicit maintainer approval.

Full details: Linked Issues check

Explanation

The change meets the coding requirements in [#26675]. ChatView.tsx omits the composer label. workspaceFocus.ts keeps the workspace data attributes and tabIndex, and adds role="region" and aria-label only when a label is supplied. The conversation area still supplies its label. The linked issue does not require a separate automated test.

Full details: Out of Scope Changes check

Explanation

The whole-PR diff changes only the composer call site and the optional-label behavior in workspaceFocus.ts. Both changes directly address [#26675]. The diff contains no demonstrated unrelated product behavior.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

maria-rcks commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

kept the original two-file fix unchanged and merged current main (d92c437) into the contributor branch. the diff remains 3 additions and 4 deletions; simplifying it further would obscure the distinction between f6 registration and optional region naming.

verification at 4ce27234ecc03ae64326e80fb02c2037ee5075c6:

  • blacksmith vp run check:changed d92c437baa19409f99416a44f748f148f4317c65 passed format, lint, knip, affected typechecks, four nearby test files, and react compiler checks.
  • real chrome client: main exposes region Message input plus textbox Message New thread; this head exposes only the textbox name. f6 and shift+f6 still move between conversation, composer, and details. conversation retains its named region.
  • all 29 ci checks are green.
  • two independent code reviews approved this head with no findings.
  • windows desktop nvda speech, macos voiceover, and hosted web remain unverified in this linux run. the original nvda report is preserved above. web and desktop share this component; mobile does not use it.

matching composer crops show the unchanged layout. the recording demonstrates f6 navigation, not screen-reader speech.

composer before on main

composer after the accessibility fix

f6 and shift-f6 navigation after the fix

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified the web accessibility change at 4ce27234ecc03ae64326e80fb02c2037ee5075c6 without code changes.

ran vp i and a background vp run dev on github/main (80a2351fcb) in a separate worktree, then stopped it before starting the exact pr head. used isolated app state with seeding disabled. created a project pointing at a real git repository through the web ui and submitted real codex gpt-6.1-sol turns through the composer. drove system google chrome with the repository playwright dependency. reused the same app-created conversation for comparison.

the live chrome accessibility tree reproduced the redundant naming on main and confirmed its removal on the pr:

main: region "Message input" > ... > textbox "Message Composer Verification"
pr:   textbox "Message Composer Verification"; no "Message input" ancestor/landmark

main and pr, from the editor:
F6       -> thread details / Open in Files
Shift+F6 -> composer / Message Composer Verification
Shift+F6 -> conversation / Conversation
F6       -> composer / Message Composer Verification
result: "keyboard draft preserved" remained intact

pr, from the enabled send button:
F6       -> thread details
Shift+F6 -> composer / Submit message
Enter    -> real codex turn submitted
response -> "follow-up composer verified."
result: composer usable for the next draft

the other named regions, including conversation, thread details, workspace and version control, remain present. the screenshot pair shows the same real conversation and draft; the accessibility tree above is the evidence for the naming change. the recording shows the follow-up submission and response, without a speech track.

main: real conversation and composer draft

pr: same conversation and composer draft

pr: keyboard submission through codex and completed response

vp run check:changed refs/remotes/verification/main passed through blacksmith-check: format, lint, both knip passes, affected typechecks, 58 tests in four files, and both selected react compiler checks. the worker initially lacked git ancestry and the playwright browser; restored history and installed chromium before the successful run. the pr head also has 29 successful ci contexts.

Not verified

actual spoken announcements with windows nvda or macos voiceover: this is a linux vm. the live chrome accessibility tree and keyboard/client/provider behavior were exercised, but they do not prove the exact words those screen readers speak. native electron, ios/android, hosted web and relay/tunnel connections were not exercised. mobile does not use the changed web composer code.

This branch has not been deployed

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

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Screen readers say "Message" twice when focus enters the composer

2 participants