A grid of data
A table holds tabular data: values set out in rows and columns, where each value means something because of its row and its column. Here, a coffee menu of drinks and prices. Tables are for data, not page layout.
<table> opens the table and </table>, on line 7, closes it. Everything between them belongs to the table. The browser sets up a grid for it, still empty until the rows arrive.
<caption> gives the table a title. It must come first, straight after <table>. Browsers draw it centred above the grid, and a screen reader announces it, so a listener can decide whether to read on.
Rows and cells
<tr> means table row. The cells written inside it sit side by side, left to right, in the order they appear. Every tr becomes one row of the grid.
<th> means table header. A header cell labels the cells that belong to it. Browsers draw header cells bold and centred, so Drink and Price stand out at the top of their columns.
<td> means table data: an ordinary cell holding one value. Line 4 is a second row with two data cells, Espresso and 2.50. Data cells are plain text, aligned to the left.
There is no tag for a column. Columns come from position: the second cell of every row lands in the second column, under Price. Each column grows to fit its widest cell.
The attribute colspan="2" stretches one cell across two columns. Line 6 is a single cell, Hot only, that spans the full width of the table, like a note under the menu.
Meaning for everyone
Inspect the page and you will find a tbody element around the four rows. You never wrote it: browsers add a table body to every table. You can write thead and tbody yourself to group header and body rows.
Header cells are more than bold text. A screen reader links each data cell to its headers, so a listener who reaches 3.75 can learn that it is a Price, without seeing the grid.
scope says which cells a header is for: scope="col" means its column, scope="row" its row. In this small table browsers work it out, but in bigger tables scope removes the guesswork.
What happens
;; step 1/11 · tabular
file menu.html (7 lines)
1 <table>
2 <caption>Coffee menu</caption>
3 <tr><th>Drink</th><th>Price</th></tr>
4 <tr><td>Espresso</td><td>2.50</td></tr>
5 <tr><td>Latte</td><td>3.75</td></tr>
6 <tr><td colspan="2">Hot only</td></tr>
7 </table>
table rows across, columns down
each value is read by its row AND its column
The figure draws faint lines between the cells so you can see the grid. Browsers draw no borders by default; a CSS rule such as th, td { border: 1px solid; } adds them. Each row is on one line here to keep the file short. You can also put every cell on its own line; the table comes out the same.