Skip to content

fix(web): role=button + aria-label on source-detail chunk cards (#700)#810

Merged
memtomem merged 1 commit intomainfrom
fix/web-a11y-chunk-card-role
May 5, 2026
Merged

fix(web): role=button + aria-label on source-detail chunk cards (#700)#810
memtomem merged 1 commit intomainfrom
fix/web-a11y-chunk-card-role

Conversation

@memtomem
Copy link
Copy Markdown
Owner

@memtomem memtomem commented May 5, 2026

Summary

Source-detail .chunk-card rows had no accessible name, and the collapsible variant — added in the rAF accordion pass when contentDiv.scrollHeight > 120 — had only mouse-click wired for expand/collapse. Screen readers announced cards as anonymous "group" landmarks and keyboard users could neither tab to a card nor expand it.

Third of three split PRs against #700 (Source detail chunk cards target). Independent of #808 (search) and #809 (timeline).

Changes (app.js, browseSource)

  • Set aria-label on every card (chunk type + line range + heading-hierarchy trail) right after card.dataset.chunkId — informational cards still need an accessible name.
  • In the requestAnimationFrame accordion-activation block, when a card becomes .chunk-card-collapsible, also set role="button" + tabindex="0" and add a keydown handler that mirrors the existing click toggle.
  • Refactor the toggle body into a local toggleCard() helper so click and keydown share one path.

The keydown handler skips when focus is in:

  • .chunk-card-actions — so a Copy/Edit/Delete button's Enter doesn't also toggle the parent card.
  • .chunk-card-edit-area — so a textarea's Enter newline doesn't collapse the card mid-edit.

Drag-vs-click detection on the click path is preserved unchanged.

tests/test_web_a11y.py — new TestChunkCardA11y class, three pin assertions:

  • aria-label is set on every card.
  • role="button" + tabindex live inside the .chunk-card-collapsible activation block (i.e. only on toggle-able cards, matching the issue's "informational" vs "clickable" distinction).
  • keydown handler exists with both required exclusion zones.

Mutation-validated: removing role= from the activation block fails the relevant test.

Why this scoping

  • Non-collapsible cards have an aria-label but no role — they're informational, not interactive. Adding role="button" to a non-toggle card would be a lie. This matches issue List-row a11y: search / sources / timeline rows lack role / aria-label #700's option-1 / option-2 distinction.
  • aria-label text uses data already on the card; no new server data, no i18n keys (chunk_type / line numbers are not localized prose).

Out of scope

Test plan

Merge interaction with #808 and #809

All three PRs touch tests/test_web_a11y.py: each creates the file with the same fixtures + helpers and adds its own test class. Whichever lands first leaves the others with a trivial rebase to keep all classes side-by-side.

Refs #700, umbrella #702.

🤖 Generated with Claude Code

Source-detail .chunk-card rows had no accessible name and the collapsible
ones had no keyboard activation — only mouse-click was wired. Screen
readers announced cards as anonymous "group" landmarks, and keyboard
users could neither focus nor expand a collapsed card.

Set aria-label unconditionally on every card (chunk type + line range +
heading-hierarchy trail). Cards that grow tall enough to be marked
.chunk-card-collapsible additionally get role="button" + tabindex="0"
and a keydown handler that mirrors the existing click toggle.

Refactor the toggle into a local toggleCard() helper so click and
keydown share one code path. The keydown handler skips when focus is in
.chunk-card-actions (so a button's Enter doesn't also collapse the
parent) or .chunk-card-edit-area (so a textarea's Enter doesn't
collapse the card mid-edit). Drag detection on click is preserved.

Pin the contract with TestChunkCardA11y in test_web_a11y.py — three
source-scan assertions: aria-label is set on every card, role=button +
tabindex live inside the .chunk-card-collapsible activation block, and
the keydown handler exists with both required exclusion zones.
Mutation-validated: removing role= from the activation block fails the
specific test.

Refs #700, umbrella #702.

Co-Authored-By: Claude <[email protected]>
@memtomem memtomem force-pushed the fix/web-a11y-chunk-card-role branch from 4f96a07 to 9fda6d9 Compare May 5, 2026 13:54
@memtomem memtomem merged commit 12d2c64 into main May 5, 2026
11 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

List-row a11y: search / sources / timeline rows lack role / aria-label

2 participants