# Tables for Data

A table holds data you read both across a row and down a column, built from rows of header and data cells with a caption that says what the table shows, and it's never used to lay out a page.

Apprentice · HTML · Updated October 31, 2026

## After this lesson you can

- Decide whether content is data for a table, and keep tables out of page layout
- Build a table with table, tr, th, td and caption

## Key takeaways

- Use a table when you read the data both ways, across a row and down a column, like a bus timetable or a price chart.
- A table is built row by row, with `<tr>`. Each row holds cells, `<th>` for a header that labels and `<td>` for data.
- A `<caption>`, the first thing inside `<table>`, is the table's title. Screen readers announce it before the cells.
- Never use a table to place things on a page. A table tells screen readers the content is data, and they may read a layout table cell by cell, which turns the page into a puzzle. Layout is CSS's job.

A bus timetable, the standings in a sports league, a phone company's plan comparison, the grade sheet in a class: these are all tables. At work you'll build them for price lists, schedules, reports and comparison charts, and they're one of the first things people expect a web page to show clearly. HTML tables are built for exactly this, and built well, they're readable by everyone, including people who listen to the page instead of looking at it.

## Is it a table? Read it both ways

Here's a quick test. Look at one value and ask what it means. In a shopping list, "milk" means milk: it needs nothing else. In a bus timetable, "8:15" means nothing on its own. You have to look **across** to see the stop (Main Street) and **up** to see the route (Route 4). When you read data both ways, across a row and down a column, it's a table.

A table like that is called a **data table**: data arranged in rows and columns, where every value belongs to both its row and its column. A spreadsheet is the everyday version.

The Galaxy Blasters arcade's price chart passes the test. What does $6.00 mean? You need its row (Turbo Kart Rally) and its column (5 plays) to know.

| Game | 1 play | 5 plays |
|---|---|---|
| Galaxy Blasters | $1.00 | $4.00 |
| Turbo Kart Rally | $1.50 | $6.00 |

![A price chart with one cell, $6.00, picked out, and arrows from it across to the game's name and up to the column's label: you need both to know what the price means](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/10/ed98dcea264143fb99a30298271a7f7d.webp)

## Rows and cells: table, tr, th and td

Four elements build a table:

- `<table>` wraps the whole table.
- `<tr>`, read "T R", is a **table row**: a row of cells, left to right.
- `<th>`, read "T H", is a **table header cell**: a cell that labels a row or a column, such as "5 plays".
- `<td>`, read "T D", is a **table data cell**: a cell that holds data, such as "$6.00".

You write the table one row at a time, from the top down, and each row's cells from left to right. Here's the price chart:

```html
<table>
    <tr>
        <th>Game</th>
        <th>1 play</th>
        <th>5 plays</th>
    </tr>
    <tr>
        <td>Galaxy Blasters</td>
        <td>$1.00</td>
        <td>$4.00</td>
    </tr>
    <tr>
        <td>Turbo Kart Rally</td>
        <td>$1.50</td>
        <td>$6.00</td>
    </tr>
</table>
```

There's no element for a column. A column is made of the cells in the same position in every row: the second cell of each row makes the "1 play" column. That's why every row needs the same number of cells, here three each.

**Try it.** In your practice folder, make `arcade-prices.html` from the page skeleton, and add the table above. Add a row for Neon Air Hockey, at $2.00 for 1 play and $8.00 for 5 plays.

## Header cells label the data

Header cells are more than bold text. When a screen reader user moves to a cell, the screen reader reads the header that labels it, so instead of hearing "$6.00" alone, they hear something like "5 plays, $6.00". The `<th>` elements are what make that possible. A browser shows them in bold and centered, but that's only the default look; their job is to say "I'm a label".

So a header cell is right for any cell that labels others, and wrong for data. "5 plays" is a header; "$4.00" is data. The name at the start of a row labels the row, so it can be a header cell too:

```html
<tr>
    <th>Turbo Kart Rally</th>
    <td>$1.50</td>
    <td>$6.00</td>
</tr>
```

The next lesson, *Table Headers, Sections and Spanning Cells*, shows how to tell the browser whether a header labels its column or its row.

## A caption: the table's title

A chart in a textbook has a title over it, so you know what it shows before you read the numbers. A table's title is its `<caption>`, and it goes **first** inside `<table>`, before any row:

```html
<table>
    <caption>Game prices</caption>
    <tr>
        <th>Game</th>
        <th>1 play</th>
        <th>5 plays</th>
    </tr>
</table>
```

When a screen reader reaches the table, it announces the caption along with the table's size, something like "table, Game prices, 3 columns, 3 rows". A listener knows what the table is about and whether to dive in, before hearing a single cell. A heading above the table helps sighted readers, but only the `<caption>` belongs to the table itself.

**Try it.** Give your price table a caption, then look at it in the browser: the caption sits centered above the table.

## Never use a table for page layout

In the early days of the web, before CSS could arrange a page, people used tables to place things: the logo in one cell, the menu in the cell beside it, the content in a big cell below. You'll still find pages built that way, and still find advice that suggests it. Don't do it:

```html
<!-- Don't do this: a table used only to put the logo beside the menu -->
<table>
    <tr>
        <td><img src="logo.png" alt="Galaxy Blasters Arcade"></td>
        <td><a href="games.html">Games</a> <a href="prices.html">Prices</a></td>
    </tr>
</table>
```

A table tells the browser "this is data in rows and columns". Browsers try to spot layout tables and hide the grid from screen readers, but it's a guess: add a header cell or a border, and a screen reader may announce a table and read the page cell by cell, with "row 1, column 2" before the menu. A layout table is also hard to change and doesn't fit a phone's narrow screen. The rule is short: **data goes in a table; placing things on a page is CSS's job.** (The CSS in Depth course teaches layout, if you want to go deeper.)

## Check yourself

2 questions to try on the lesson page.

## So what

Price lists, schedules, scores and reports are tables, and a table with header cells and a caption can be read by everyone: at a glance by sighted readers, and cell by cell, with its labels, by screen reader users.

## Key terms

- [Data table](https://www.ask-codey.com/glossary/data-table)
- [Table row](https://www.ask-codey.com/glossary/table-row)
- [Table header cell](https://www.ask-codey.com/glossary/table-header-cell)
- [Table data cell](https://www.ask-codey.com/glossary/table-data-cell)
- [&lt;caption>](https://www.ask-codey.com/glossary/caption)

## Cheat sheets

- [Tables for Data](https://www.ask-codey.com/cheat-sheets/html-tables-for-data-cheat-sheet)

## Related

- [Description Lists](https://www.ask-codey.com/lessons/html-description-lists)
- [Table Headers, Sections and Spanning Cells](https://www.ask-codey.com/lessons/html-table-headers-and-spanning)

Source: https://www.ask-codey.com/lessons/html-tables-for-data
