Skip to content

Stop every console list from hiding itself from screen readers - #5

Merged
sylvesterdamgaard merged 1 commit into
mainfrom
fix/a11y-list-rows
Jul 27, 2026
Merged

Stop every console list from hiding itself from screen readers#5
sylvesterdamgaard merged 1 commit into
mainfrom
fix/a11y-list-rows

Conversation

@sylvesterdamgaard

Copy link
Copy Markdown
Contributor

role="link" on a <tr>, with a paired aria-label, on 30 rows across 27 files — every list in the console.

It overrides the row's row role, collapsing the table's row/column relationships for the whole table; and because a link takes its accessible name from the author, the aria-label replaces the subtree. A screen-reader operator on /console/invoices heard "Open invoice INV-1042, link" and nothing else — no way to learn what any invoice was worth or whether it was paid.

Removing that one attribute fixes both. Rows stay focusable via tabindex, keep their aria-label (which names a row without hiding it), and the existing delegated keydown handler still navigates on Enter.

Deliberately not the larger restructure into a first-cell anchor: 7 of the 30 rows have first cells the transform could not safely rewrite, and a partial migration would leave the console inconsistent for no additional accessibility gain today. Tracked separately.

Bypass block

Adds a skip link as the first focusable element and <main id="content"> in both layouts. <main> previously appeared exactly once in the whole application (the paywall), so landmark navigation found nothing and reaching the first row cost ~25 tab stops on every load.

A test that codified the bug

ConsoleUxFoundationTest asserted role="link" was present, describing it as "the accessible pattern". The intent was right — ban inline onclick navigation — but it locked in the wrong mechanism, which is how the attribute survived on 30 rows. It now asserts the opposite, alongside new guards for landmarks and the skip link.

Gate

pint · PHPStan level max (0 errors) · 1032 tests — green.

…ders

`role="link"` on a <tr>, with a paired aria-label, appeared on 30 rows across 27
files — every list in the console. It does two things, both bad:

  - it overrides the row's `row` role, which collapses the table's row/column
    relationships for the WHOLE table; and
  - a link takes its accessible name from the author, so the aria-label REPLACES
    the subtree.

A screen-reader operator on /console/invoices therefore heard "Open invoice
INV-1042, link" and nothing more — no way to learn what any invoice was worth or
whether it was paid. On every list, on every page.

Removing that one attribute fixes both: the rows stay focusable via tabindex, keep
their aria-label (which NAMES a row without hiding it), and the existing delegated
keydown handler still navigates on Enter. Deliberately not the larger restructure
into a first-cell anchor — 7 of the 30 rows have first cells the transform could not
safely rewrite, and a partial migration would leave the console inconsistent for no
additional accessibility gain today. Tracked separately.

Also adds the bypass block that was missing entirely: a skip link as the first
focusable element, and <main id="content"> in BOTH layouts. `<main>` previously
appeared exactly once in the whole application (the paywall), so landmark navigation
found nothing and reaching the first table row cost ~25 tab stops on every load.

AND CORRECTS A TEST THAT CODIFIED THE BUG. ConsoleUxFoundationTest asserted
`role="link"` was present, calling it "the accessible pattern". Its intent was right
— ban inline onclick navigation — but it locked in the wrong mechanism, which is how
the attribute survived on 30 rows. It now asserts the opposite. A test can enshrine a
defect as thoroughly as it can catch one.
@sylvesterdamgaard
sylvesterdamgaard merged commit fcf87ed into main Jul 27, 2026
2 checks passed
@sylvesterdamgaard
sylvesterdamgaard deleted the fix/a11y-list-rows branch July 27, 2026 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant