HTML Tables
Build tabular data layouts correctly with table, thead, tbody, and the accessibility attributes that make them usable.
2 min read
Tables are for tabular data — rows and columns of related values, like a spreadsheet. (They were once misused for entire page layouts before CSS could do that job properly — don't reach for a table just to arrange boxes on a page.)
The basic structure
<table>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Years</th>
</tr>
</thead>
<tbody>
<tr>
<td>Amara</td>
<td>Engineer</td>
<td>4</td>
</tr>
<tr>
<td>Diego</td>
<td>Designer</td>
<td>2</td>
</tr>
</tbody>
</table><table>wraps the whole thing.<thead>groups the header row(s);<tbody>groups the data rows.<tr>is a table row.<th>is a header cell (bold and centered by default);<td>is a regular data cell.
Why <th> matters for accessibility
A screen reader announces column headers as it reads through a table's cells — "Name: Amara. Role: Engineer." — but only if headers are marked with <th> rather than styled <td> cells that merely look like headers. Using <th> (with scope="col" or scope="row" when it's ambiguous) is what makes a table's data actually parseable by someone who can't see the grid.
<th scope="col">Role</th>Spanning cells
<table>
<tr>
<th>Quarter</th>
<th colspan="2">Revenue</th>
</tr>
<tr>
<td></td>
<td>Domestic</td>
<td>International</td>
</tr>
</table>colspan— makes a cell span multiple columns.rowspan— makes a cell span multiple rows.
Adding a caption
<table>
<caption>Team roster, updated quarterly</caption>
<thead>
<tr><th>Name</th><th>Role</th></tr>
</thead>
<tbody>
<tr><td>Amara</td><td>Engineer</td></tr>
</tbody>
</table><caption> describes what the table represents — like alt text for tabular data — and is announced by screen readers before the table's contents.
A rule of thumb
If you find yourself using a table purely to align boxes visually rather than to present rows and columns of related data, that's a sign you want CSS Grid or Flexbox instead — those are covered in the CSS course.