HTML Tables
Structure tabular data with table, thead, tbody, th, td — and when NOT to use tables
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
Tables are for tabular data — information that has a natural row/column relationship. They are not for page layout.
Basic table structure:
html <table> <thead> <tr> <th scope="col">Name</th> <th scope="col">Score</th> <th scope="col">Grade</th> </tr> </thead> <tbody> <tr> <td>Alice</td> <td>92</td> <td>A</td> </tr> <tr> <td>Bob</td> <td>78</td> <td>C+</td> </tr> </tbody> <tfoot> <tr> <td>Average</td> <td>85</td> <td>B</td> </tr> </tfoot> </table>
Key elements:
| Element | Purpose | |---|---| | <table> | Container for the entire table | | <thead> | Group of header rows | | <tbody> | Group of data rows | | <tfoot> | Summary/footer rows (totals, averages) | | <tr> | Table row | | <th> | Header cell — bold by default, read by screen readers as column/row header | | <td> | Data cell | | <caption> | A title for the table (recommended for accessibility) |
`scope` on `<th>`:
html <th scope="col">Name</th> <!-- This header applies to the column below it --> <th scope="row">Total</th> <!-- This header applies to the row to its right --> scope` tells screen readers which cells a header describes — important for complex tables.
Spanning cells:
html <!-- colspan: cell spans 2 columns --> <td colspan="2">Merged</td> <!-- rowspan: cell spans 3 rows --> <td rowspan="3">Category</td>
Caption:
html <table> <caption>Q2 2026 Sales by Region</caption> ... </table>
When NOT to use tables: Never use <table> for page layout — use CSS Grid or Flexbox. Tables in the 1990s were used for layout; screen readers still read them as data tables, which breaks accessibility.
Examples
Comparison table with caption and scope
Row headers (`scope="row"`) and column headers (`scope="col"`) let screen readers associate every cell with both its row and column header
<table>
<caption>Pricing Plans Comparison</caption>
<thead>
<tr>
<th scope="col">Feature</th>
<th scope="col">Free</th>
<th scope="col">Pro ($12/mo)</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Tracks</th>
<td>1 (Fundamentals)</td>
<td>All tracks</td>
</tr>
<tr>
<th scope="row">Practice modes</th>
<td>Quiz only</td>
<td>All modes</td>
</tr>
<tr>
<th scope="row">Progress tracking</th>
<td>Basic</td>
<td>Full with cloud sync</td>
</tr>
</tbody>
</table>Table with colspan and rowspan
`colspan` merges across columns; `rowspan` merges down rows — the total cell count per row must still add up correctly
<table>
<caption>Project Schedule</caption>
<thead>
<tr>
<th scope="col">Task</th>
<th scope="col">Week 1</th>
<th scope="col">Week 2</th>
<th scope="col">Week 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Design</th>
<td colspan="2">In progress</td> <!-- spans Week 1 & 2 -->
<td>Review</td>
</tr>
<tr>
<th scope="row">Development</th>
<td>—</td>
<td rowspan="2">Building</td> <!-- spans Development & Testing rows -->
<td>Launch</td>
</tr>
<tr>
<th scope="row">Testing</th>
<td>—</td>
<td>Done</td>
</tr>
</tbody>
</table>How well did you understand this?
Next in HTML
HTML Accessibility Basics