Tables
Why you need this
A train timetable, a results table, a comparison of plans, a price list — data that has rows and columns. HTML has tables for that. Important: tables are for data, not for laying out a page in columns (people did that in the 2000s; today there are Flexbox and Grid for it — topics 13–14).
Rows and cells
A table is built row by row:
<table>— the whole table;<tr>(table row) — a row;<td>(table data) — a cell inside a row.
<table>
<tr>
<td>Apples</td>
<td>$2</td>
</tr>
<tr>
<td>Pears</td>
<td>$3</td>
</tr>
</table>
Result: 2 rows of 2 cells. No borders — the browser doesn't draw them by default.
There are no separate tags for columns: a column appears by itself — from the first cells of all rows, the second ones, and so on. That's why every row must have the same number of cells.
Header cells <th>
<th> (table header) is a header cell. Its text is bold and centred, and screen readers understand
that it is the name of a column:
<table>
<tr>
<th>Product</th>
<th>Price</th>
</tr>
<tr>
<td>Apples</td>
<td>$2</td>
</tr>
</table>
Result: the first row is bold — it is the table header.
Parts of a table and the caption
Big tables are split into parts:
<caption>— the table title, goes right after<table>;<thead>— the header;<tbody>— the main data;<tfoot>— the totals row.
<table>
<caption>Shopping</caption>
<thead>
<tr><th>Product</th><th>Price</th></tr>
</thead>
<tbody>
<tr><td>Bread</td><td>1</td></tr>
<tr><td>Cheese</td><td>6</td></tr>
</tbody>
<tfoot>
<tr><td>Total</td><td>7</td></tr>
</tfoot>
</table>
Result: the title «Shopping» above the table, a bold header, two data rows and a «Total» row.
Merging cells
A cell can be stretched over several columns — colspan — or rows — rowspan:
<table border="1">
<tr><th colspan="2">Contacts</th></tr>
<tr><td>Phone</td><td>123-45-67</td></tr>
<tr><td rowspan="2">Email</td><td>work@mail.com</td></tr>
<tr><td>home@mail.com</td></tr>
</table>
Result: «Contacts» is one wide cell over both columns; «Email» is a tall cell over two rows with two addresses to its right.
Note: the last row has one cell — the second place is already taken by the stretched «Email».
Count it like this: every row takes the same number of columns in total, including colspan and
rowspan from above.
border="1"is an old quick way to show borders. Real projects set borders in CSS:td, th { border: 1px solid gray; }.
How it works inside
The browser first reads all rows and then calculates the column widths: each column is made wide enough
for the longest text in it. If you don't write <tbody> in a <table>, the browser adds it itself — it
appears in the DOM even if it's not in the code.
Common mistakes
- Text directly in
<tr>.<tr>Apples</tr>— text must live in a<td>or<th>. - A different number of cells in rows. The table "breaks": columns shift and empty spots appear on the right.
colspanwithout removing extra cells. You stretched a cell over 2 columns — the row must now have one cell fewer.<caption>not first. The caption must come right after the opening<table>.- A table for layout. Site columns made with
<table>work badly on phones. Tables are for data only.
Cheat sheet
| Tag / attribute | What it does |
|---|---|
<table> |
a table |
<tr> |
a row |
<td> / <th> |
a cell / a header cell |
<caption> |
the table title (first inside <table>) |
<thead>, <tbody>, <tfoot> |
header, body, totals |
colspan="2" |
stretch over 2 columns |
rowspan="2" |
stretch over 2 rows |