Tables
Prerequisites: Lists
Tables are for tabular data — information with rows and columns, like a timetable, a price list, or sports results.
<table>
<caption>Opening hours</caption>
<thead>
<tr>
<th scope="col">Day</th>
<th scope="col">Opens</th>
<th scope="col">Closes</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Monday</th>
<td>07:00</td>
<td>18:00</td>
</tr>
<tr>
<th scope="row">Saturday</th>
<td>08:00</td>
<td>14:00</td>
</tr>
</tbody>
</table>
table— the whole table.caption— the table's title. It must be the first child. It's shown above the table and announced by screen readers.tr— a table row.th— a header cell;td— a data cell.scope="col"/scope="row"— says whether a header labels a column or a row. Screen readers then announce "Saturday, Closes, 14:00" as a user moves through cells.thead,tbody,tfoot— group rows into head, body, and foot sections.
Without CSS, tables have no borders. Styling comes later.
Spanning cells
<table>
<caption>Class schedule</caption>
<tr>
<th scope="col">Time</th>
<th scope="col">Monday</th>
<th scope="col">Tuesday</th>
</tr>
<tr>
<th scope="row">09:00</th>
<td rowspan="2">Chemistry (double)</td>
<td>Math</td>
</tr>
<tr>
<th scope="row">10:00</th>
<td>History</td>
</tr>
<tr>
<th scope="row">11:00</th>
<td colspan="2">Sports day</td>
</tr>
</table>
rowspan="2" makes a cell two rows tall; colspan="2" makes it two
columns wide. The next row has one fewer td, because the spanning
cell already fills that slot.
The validator checks that rows add up:
<!-- Wrong: the second row has too many cells -->
<table>
<tr><th scope="col">Name</th><th scope="col">Age</th></tr>
<tr><td>Ada</td><td>36</td><td>London</td></tr>
</table>
warning: A table row was 3 columns wide and exceeded the column count established by the first row (2).
Don't use tables for layout
In the early web, whole pages were laid out with tables. Don't: it confuses screen readers (which announce rows and columns) and makes responsive design hard. Use CSS Grid and Flexbox for layout.
Our HTML Table Generator builds table markup from rows you type in.
Practice
Make a table with a caption "Team scores", columns "Team" and "Points",
two teams as row headers, and a tfoot row showing the total.
Show solution
<table>
<caption>Team scores</caption>
<thead>
<tr><th scope="col">Team</th><th scope="col">Points</th></tr>
</thead>
<tbody>
<tr><th scope="row">Red</th><td>12</td></tr>
<tr><th scope="row">Blue</th><td>9</td></tr>
</tbody>
<tfoot>
<tr><th scope="row">Total</th><td>21</td></tr>
</tfoot>
</table>