Skip to content

[6.x] Expose aria-sort on sortable listing column headers - #15403

Merged
jackmcdade merged 1 commit into
statamic:6.xfrom
bpmore:fix/listing-aria-sort
Sep 8, 2026
Merged

jackmcdade merged 1 commit into
statamic:6.xfrom
bpmore:fix/listing-aria-sort

Conversation

@bpmore

@bpmore bpmore commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #15398.

Listing column headers are buttons that sort the table, but aria-sort was never set on the <th> — before or after sorting. A screen reader user can trigger a sort and gets no confirmation of which column is active or in which direction.

grep -rn "aria-sort" resources/js returned zero matches across the whole Control Panel.

WCAG 2.1 SC 1.3.1 and SC 4.1.2 (both Level A). Affects every listing: entries, terms, assets, users, forms, submissions, roles, groups.

The change

HeaderCell.vue already had everything needed — it computes isCurrentSortColumn and reads sortDirection from the listing context. This just binds them:

const ariaSort = computed(() => {
    if (!props.column.sortable) return null;
    if (!isCurrentSortColumn.value) return 'none';
    return sortDirection.value === 'asc' ? 'ascending' : 'descending';
});
<th scope="col" :aria-sort="ariaSort">

Non-sortable columns get no attribute at all, which is correct — aria-sort on a column that cannot be sorted would be misleading.

Tests

Added resources/js/tests/components/ListingHeaderCell.test.js with three cases:

  • a sortable column that is not the active sort column is aria-sort="none"
  • the active sort column reports ascending / descending
  • a non-sortable column has no aria-sort

Confirmed the tests fail against the unpatched component (2 of 3 fail; the third guards against regression) and pass with it.

Full unit suite: 566 passed, 9 failed. Those 9 are pre-existing LivePreview failures on a clean 6.x checkout (localStorage is not available in the unit environment) — the same 9 fail without this branch. Net effect of this PR is +3 tests, no change to existing results.

Notes

Found during a WCAG 2.1 AA audit of the CP. AI tools were used to draft this; the change, the tests, and the before/after verification were reviewed by hand.

Listing headers are buttons that sort the table, but the sort state was
never exposed to assistive technology. HeaderCell already computes
isCurrentSortColumn and reads sortDirection, so this binds them to
aria-sort on the th.

Fixes statamic#15398

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013YZV7JD2cyMHSeSu2fUXCK
@jackmcdade
jackmcdade merged commit 74c0ebd into statamic:6.x Sep 8, 2026
62 checks passed
@jackmcdade

Copy link
Copy Markdown
Member

Thank you!

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.

[6.x] Sortable listing column headers never set aria-sort

2 participants