HTML Tables Done Right: Accessible, Responsive, and Readable

Tables get a bad rap because they were misused for layout in the 2000s. Used correctly โ for actual rows and columns of data โ they're semantic, accessible, and surprisingly easy to make responsive.
Semantic table structure
<table>
<caption>Quarterly sales</caption>
<thead>
<tr><th scope="col">Quarter</th><th scope="col">Revenue</th></tr>
</thead>
<tbody>
<tr><th scope="row">Q1</th><td>$120k</td></tr>
<tr><th scope="row">Q2</th><td>$155k</td></tr>
</tbody>
</table>Why scope and caption matter
Screen readers use scope to announce which header a cell belongs to. caption gives the table a name in the accessibility tree โ better than a heading next to it.
Making tables responsive
Option 1: horizontal scroll
.table-wrap { overflow-x: auto; }
table { min-width: 600px; border-collapse: collapse; }Option 2: stack rows on mobile
@media (max-width: 640px) {
thead { display: none; }
tr, td { display: block; width: 100%; }
td::before { content: attr(data-label); font-weight: 600; display: block; }
}Quick accessibility checklist
- Always include <caption>
- Use <th scope="col"> and <th scope="row">
- Don't nest tables
- Keep header text short and meaningful
- Avoid colspan/rowspan if you can โ they confuse screen readers
Frequently asked questions
Should I use a CSS framework's table component?
It's fine for styling, but make sure the underlying markup keeps <thead>, <th scope>, and <caption> โ many frameworks drop them.
Can I sort columns without JavaScript?
Not natively. You'll need a small script or a library like list.js. Keep the unsorted state semantic.
Keep reading
External references
Enjoyed this article?
Share it with a fellow developer or explore more tutorials in our blog.
More articles