Tables beyond sorting: help the table keep its meaning
When we talk about “accessible tables”, we often jump straight to sorting. But a big chunk of table accessibility is simpler: the user should be able to understand what each cell means even if they can’t see the layout.
Live demo (BEFORE vs AFTER): Open tables beyond sorting demo
What goes wrong
- No caption. The user doesn’t get the “what is this table?” summary up front (e.g., “Level 1 leaderboard”).
- No real headers. Column labels (“Score”, “Time”) are just visually bold text, not
<th>elements. - No header association. Even if you use
<th>, missing or incorrectscopecan make context unclear.
The fix (small, reliable pattern)
- Use a real
<table>with<thead>/<tbody>. - Add a meaningful
<caption>.- Make it short, like a title: “Level 1 leaderboard” or “Monthly expenses (USD)”.
- It’s OK to include a tiny qualifier: “(sample data)”.
- Mark header cells with
<th>, not styled<td>or<div>. - Use
scopeso the header relationship is explicit:<th scope="col">for column headers<th scope="row">for row headers (when applicable)
Rule of thumb
If you removed the grid lines, removed the bold styling, and read the table aloud cell-by-cell, would a listener still understand what each number refers to? Captions and headers are how you preserve that meaning.
Common gotchas
- Don’t use a “table-like” div grid for real tabular data. It often loses header relationships.
- Don’t skip the caption. A good caption prevents “what am I looking at?” confusion.
- Don’t rely on position alone. Screen readers announce context like “Score, 12” when headers are wired correctly.