Data tables are among the most complex components to make accessible. Sorting, filtering, pagination, and responsive collapse all have accessibility implications that most table libraries ignore entirely.
The Challenges
Sorting — when a column is sorted, screen readers need to know which column is active and in which direction. aria-sort on the <th> element handles this, but must be updated on each sort change.
Filtering — filter results must be announced. A live region that reports "Showing 12 of 47 results" keeps screen reader users informed without requiring them to re-read the table.
Keyboard navigation — users should be able to navigate cells with arrow keys, not just Tab. This requires a roving tabindex implementation where only one cell is in the tab sequence at a time.
Responsive collapse — on small screens, tables collapse to card layouts. Each card must maintain the association between label and value that the table header provided visually.
<th
aria-sort={sortKey === column.key
? sortDir === 'asc' ? 'ascending' : 'descending'
: 'none'}
>
<button onClick={() => onSort(column.key)}>
{column.label}
</button>
</th>
The Outcome
The component replaced three separate table implementations across the product. Screen reader testing confirmed that VoiceOver, NVDA, and TalkBack users could complete all table tasks without assistance.