Skip to content

fix(web): restore sidebar thread list and row actions for NVDA - #13910

Closed
gabrielelpidio wants to merge 1 commit into
mainfrom
fix/sidebar-thread-list-role
Closed

gabrielelpidio wants to merge 1 commit into
mainfrom
fix/sidebar-thread-list-role

Conversation

@gabrielelpidio

@gabrielelpidio gabrielelpidio commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

#13491 regressed the sidebar for NVDA users, as reported by @akj in #13491 (comment):

  1. The thread <ul> was set to role="presentation", so NVDA no longer announces "list with N items" and its L/I quick-nav keys skip the threads.
  2. Each row (role="button") gained an aria-label. NVDA's browse mode reads that label in place of the row's contents, which hides the nested Snooze and Settle buttons.

This restores role="list" and drops the row aria-labels, so each row's name comes from its contents again. The screen-reader-only title that already leads each row keeps the title first. aria-current and the non-focusable scroll viewport (viewportTabIndex={-1}) from #13491 stay. Search results keep their label, since those listbox options have no nested actions. The now-unused resolveSidebarRowAccessibility helper and its tests are removed.

The change is @akj's, from their branch fix/sidebar-nvda-row-actions, and they are credited as co-author.

Verification

Checked Chrome's accessibility tree against a dev server with real data:

main This PR
Thread <ul> role="presentation" list with a listitem per row
Row name "Fix Large Chat Thread Crash, t3chat-new" (label only) "Fix Large Chat Thread Crash t3chat-new 9d Snooze thread Settle thread …"
Snooze / Settle present in the tree, but hidden behind the label in NVDA browse mode exposed buttons, part of the row's name

No visual change: before and after screenshots of the sidebar are identical. Sidebar logic tests, web typecheck and lint pass.

Not yet tested with real NVDA or VoiceOver. #13491 changed the list role to avoid a VoiceOver interaction boundary. @akj suspects the focusable scroll viewport caused that boundary, and #13491 already fixed the viewport. VoiceOver still needs checking. If the list still traps VoiceOver, we can revert just the list role and keep the label removal.

🤖 Generated with Claude Code (Claude Opus 5.5)

Summary by CodeRabbit

  • Accessibility
    • Sidebar items now expose active-page status directly to assistive technologies.
    • Unsent drafts are identified in screen-reader text, and search results include the project name when available.
    • Thread titles provide accessible text, and thread items are presented as a list.

The thread list was flattened to role="presentation", so NVDA lost list
semantics and list quick navigation. Each row also gained an aria-label,
which NVDA's browse mode reads instead of the row's contents, hiding the
nested Settle and Snooze buttons.

Restore role="list" and drop the row aria-labels. The screen-reader-only
title that already leads each row keeps the title first in the name, and
aria-current and the non-focusable scroll viewport stay as they were.

Co-authored-by: Andrew Johnson <andrew@johnson5.net>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB +16 B (+0.1%) 15.1 KiB ✅
Codex Thread snapshot wire 7.1 KiB 7.1 KiB +2 B (+0.0%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.4 KiB 6.4 KiB +14 B (+0.2%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 56.2 KiB 56.2 KiB 0 B (0.0%) 66.4 KiB ✅
Codex Live turn messages 9 9 0 (0.0%) 21 ✅
Claude Total thread wire 13.5 KiB 13.5 KiB −11 B (−0.1%) 15.1 KiB ✅
Claude Thread snapshot wire 7.1 KiB 7.1 KiB −3 B (−0.0%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB −8 B (−0.1%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 57.0 KiB 57.0 KiB 0 B (0.0%) 66.4 KiB ✅
Claude Live turn messages 9 9 0 (0.0%) 21 ✅

Baseline: ab09917 · PR result: 6d397f7 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 114.0 KiB
  • Claude decoded thread snapshot: 114.7 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a focused accessibility regression fix that restores list navigation and exposes nested sidebar actions to screen readers. Changing the production list semantics may affect VoiceOver navigation, and the documented verification does not rule out that cross-screen-reader side effect.

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

@gabrielelpidio

Copy link
Copy Markdown
Contributor Author

Closing for now while we verify the NVDA behavior firsthand. The branch is kept so this can be reopened.

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant