Home / HTML Tutorial / Day 4
Day 4 — Tables that are actually tables
Tables are for data. If you are using one to position things on a page, stop - that is Day 9.
The smallest table
<table>
<tr>
<td>Excel</td>
<td>6 weeks</td>
</tr>
<tr>
<td>SQL</td>
<td>4 weeks</td>
</tr>
</table>
tr is a row, td is a cell. Rows go down, cells go across inside them.
Headers, and the attribute nobody uses
<th> is a header cell. Add scope and a screen reader can announce "Duration: 6 weeks" instead of reading a wall of disconnected numbers.
<table>
<caption>Course durations, 2026 batches</caption>
<thead>
<tr>
<th scope="col">Course</th>
<th scope="col">Duration</th>
<th scope="col">Fee</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Advanced Excel</th>
<td>6 weeks</td>
<td>12,000</td>
</tr>
<tr>
<th scope="row">Power BI</th>
<td>5 weeks</td>
<td>14,000</td>
</tr>
</tbody>
</table>
| Part | Job |
|---|---|
<caption> | The table’s title. Goes first, inside the table. |
<thead> | The header row or rows. |
<tbody> | The data. |
<tfoot> | Totals. |
scope="col" | This th labels the column below it. |
scope="row" | This th labels the row beside it. |
Cells that span
<table>
<thead>
<tr>
<th scope="col">Course</th>
<th scope="col" colspan="2">Batches</th>
</tr>
<tr>
<th scope="col"></th>
<th scope="col">Weekday</th>
<th scope="col">Weekend</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Excel</th>
<td>7am</td>
<td>10am</td>
</tr>
<tr>
<th scope="row">SQL</th>
<td colspan="2">On request</td>
</tr>
</tbody>
</table>
Count your cells
Every row must add up to the same number of columns, counting a
colspan="2" as two. Get it wrong and the table goes crooked with no error message anywhere. When a table looks broken, count the cells in each row first.A total row
<table>
<caption>Enrolments this quarter</caption>
<thead>
<tr><th scope="col">Month</th><th scope="col">Students</th></tr>
</thead>
<tbody>
<tr><th scope="row">January</th><td>42</td></tr>
<tr><th scope="row">February</th><td>38</td></tr>
<tr><th scope="row">March</th><td>51</td></tr>
</tbody>
<tfoot>
<tr><th scope="row">Total</th><td>131</td></tr>
</tfoot>
</table>
When not to use a table
The test
Would this make sense as a spreadsheet, with meaningful rows and columns? Then it is a table.
Are you only using it to get two things side by side? Then it is not - that is a layout job, and Flexbox on Day 9 does it properly. Table layouts collapse badly on phones and confuse screen readers, which announce "table with 3 rows" before reading your navigation menu.
Are you only using it to get two things side by side? Then it is not - that is a layout job, and Flexbox on Day 9 does it properly. Table layouts collapse badly on phones and confuse screen readers, which announce "table with 3 rows" before reading your navigation menu.
Tables on a phone
A wide table on a 360px screen either squashes into unreadable columns or pushes the whole page sideways. The usual fix is to let the table scroll inside its own box.
<div style="overflow-x: auto">
<table>
<thead>
<tr>
<th scope="col">Course</th><th scope="col">Duration</th>
<th scope="col">Fee</th><th scope="col">Batch</th>
<th scope="col">Trainer</th><th scope="col">Mode</th>
</tr>
</thead>
<tbody>
<tr>
<td>Advanced Excel</td><td>6 weeks</td><td>12,000</td>
<td>Weekday</td><td>Anita</td><td>Classroom</td>
</tr>
</tbody>
</table>
</div>
The wrapper scrolls sideways instead of the whole page. You will meet this pattern again on Day 10.
Try these yourself
- Build a table of five courses with columns for duration and fee, using thead and tbody.
- Add a caption and scope attributes to every header cell.
- Add a tfoot row with the total fee.
- Deliberately give one row too few cells, run it, and see what the table does.
- Give one example of data that belongs in a table and one that does not.
