Sortable tables: don’t hide the sort state
A sortable table is still a table: rows and columns with headers. The accessibility problem usually happens when we
make the headers “clickable” by styling plain text — or by making the entire <th> behave like a button.
That breaks keyboard access and hides the sort state from assistive technology.
Live demo (BEFORE vs AFTER): Open sortable tables demo
The fix (small, reliable pattern)
- Keep real table semantics:
<table>,<caption>,<thead>,<tbody>,<th scope=\"col\">. - Put an actual interactive control inside the header:
<th><button>Name</button></th>. - Expose sort state with
aria-sorton the active header cell:aria-sort=\"ascending\"oraria-sort=\"descending\"on the active column’s<th>.- Set
aria-sort=\"none\"on the others (or omit it — but be consistent).
Gotchas worth avoiding
- Don’t rely on visual arrows alone. They’re fine as a cue, but the state must be in the accessibility tree (
aria-sort). - Don’t make the entire header cell clickable. A focused, obvious button target is more predictable.
- Sort numbers as numbers. “1205” should not sort before “980” because of string comparison.
- Keep focus stable. Sorting should not throw keyboard users back to the top of the page.
- Announce changes. A small
aria-live=\"polite\"status line can confirm the new sort order.
Rule of thumb
If the user can’t (1) reach the header control with Tab, (2) sort using Enter/Space, and (3) understand the current sort order without seeing the screen — it’s not done yet.