HTML Table Headers and Captions
Headers and a caption turn a raw grid of cells into a table that names its own columns, groups its rows, and reads correctly to a screen reader.
This builds on HTML table basics. If tags and nesting are new to you, start with the HTML guide.
Syntax
<table>
<caption>Table title</caption>
<thead>
<tr>
<th scope="col">Heading</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data</td>
</tr>
</tbody>
</table> How Do You Mark an HTML Table Header?
The th element marks a cell as a header instead of plain data. Browsers render it bold and centered by default, but its job is semantic. It tells assistive technology that this cell labels the data cells near it. Swap a td for a th anywhere a cell is acting as a label rather than a value.
<table>
<tr>
<th>Drink</th>
<th>Price</th>
</tr>
<tr>
<td>Espresso</td>
<td>3.00</td>
</tr>
</table> Headers do not have to sit only in the top row. A table can also have a header at the start of each row, for example a row that begins with a day name and then lists values for that day.
Why Is a Bold Table Cell Not a Header?
A td styled with bold, centered text can look exactly like a th on screen, and that similarity is the trap. Bold CSS does not give a td the header semantics of a th, so styling alone does not identify the cells it labels. Keep th for anything that is a header, and restyle it with CSS instead of swapping it for a td that only looks the part.
How Do HTML Table Row Groups Work?
HTML row groups separate header rows in thead, main data in tbody, and a summary in tfoot. These groups help organize markup and target CSS. They do not make headers sticky while scrolling; that requires CSS.
<table>
<thead>
<tr>
<th scope="col">Drink</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Espresso</td>
<td>3.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Total</td>
<td>3.00</td>
</tr>
</tfoot>
</table> Place tfoot after the body rows in current HTML. Older tutorials sometimes put it before tbody, but that is not the current content order.
A short table of three or four rows does not need the full split. A bare header row followed by data rows is still valid, complete markup on its own. Reach for thead, tbody, and tfoot once a table grows long enough to scroll or picks up a summary row, because that is when the extra sectioning pays off.
What Does scope Do in an HTML Table?
The HTML scope attribute identifies which cells a th labels. Use col for a column and row for a row. Browsers can infer simple associations, but explicit scope makes your intention clearer.
<table>
<thead>
<tr>
<th scope="col">Day</th>
<th scope="col">Hours</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Monday</th>
<td>Closed</td>
</tr>
</tbody>
</table> Here the top cells scope to their columns and the day cell scopes to its row, so a screen reader can announce both the column and the row header for any value. Add scope to every header cell and the table stays readable when nobody can see the grid.
Some screen readers make a reasonable guess on a small, simple table even without scope, but that guess breaks down once a table has more than one header row or mixes row headers with column headers. Write scope explicitly.
How Do You Add an HTML Table Caption?
The caption element gives the table a visible title, and it must be the very first child inside table, before any rows. It reads out as the table's name to assistive technology, so a reader who jumps between tables knows which one they landed on.
<table>
<caption>Opening hours this week</caption>
<thead>
<tr>
<th scope="col">Day</th>
<th scope="col">Hours</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Monday</th>
<td>Closed</td>
</tr>
</tbody>
</table> Example
This builds on the basic table structure. For a header that covers several columns, see the colspan and rowspan examples.
<table>
<caption>Weekend coffee prices</caption>
<thead>
<tr>
<th scope="col">Drink</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Espresso</th>
<td>3.00</td>
</tr>
<tr>
<th scope="row">Cold brew</th>
<td>4.50</td>
</tr>
</tbody>
</table> This renders with the caption above the grid, a bold header row, and a bold header cell starting each data row. The markup associates each price with its row and column headers and gives the table a caption. Exact announcements depend on the screen reader, browser, and settings.
Frequently Asked Questions
How does an HTML table caption differ from a nearby heading?
An HTML caption belongs to its table and can provide its accessible name. A nearby heading is separate unless you explicitly connect it, for example with aria-labelledby. Use caption for a short table title.
When should an HTML table use the headers attribute?
The HTML headers attribute lists the IDs of header cells associated with a data cell. Use it for relationships too complex for scope alone, or simplify the data into smaller tables.
Is the HTML table summary attribute still valid?
The HTML table summary attribute is obsolete. Put a short title in caption and any longer explanation in visible text near the table so all readers can use it.
Can an HTML table caption be visually hidden?
An HTML table caption can use a visually hidden CSS class that keeps it available to assistive technology. Do not use display: none or visibility: hidden when you want screen readers to access the caption.
Should an HTML layout table have headers?
An HTML layout table should not have data headers or a caption. Use CSS for web page layout. If an email template requires a layout table, role="presentation" can prevent it being exposed as a data table.
Sources
-
[1]
HTML Living Standard: Tabular data(html.spec.whatwg.org)
-
[2]
The Table Header element(developer.mozilla.org)
-
[3]
The Table Caption element(developer.mozilla.org)
-
[4]
Tables Tutorial(w3.org)
- [5]
Read Next
Use colspan and rowspan to let one HTML table cell cover several columns or rows, and keep the grid math straight so columns stay aligned.
Load a CSV file in the browser, parse it correctly, render a real accessible table, and follow the path into SQL when the preview becomes an import.
Build real HTML tables for tabular data: the table, tr, and td grid model, headers and captions, spanning cells, and accessible markup.