<thead> Table head
Wraps the header row or rows of a table.
<thead> wraps the rows that hold column headers. It sits after the caption and any colgroups, before the body.
Browsers and assistive technology use it to understand the table, and a long table that gets printed can repeat its header on each page. thead does not turn cells into headers by itself. The header cells inside it still have to be <th> elements.
The thead element in the HTML Living Standard (opens in a new tab) places it after caption and colgroup. The header cells are th elements.
Syntax
<table>
<thead>
<tr>
<th scope="col">Heading</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data</td>
</tr>
</tbody>
</table>When to use it
If the first row (or first few rows) of a data table name the columns, wrap them in <thead>. Order histories, league tables and price lists all qualify. Once the header is its own group, you can style it separately, pin it while the body scrolls and get it repeated on printed pages of a long report.
A table with one header row works without thead too, provided the header cells are <th>. What thead adds is a header group the browser can recognise, instead of a first row it cannot tell apart from the data. Leave it out of tables whose headers all run down the left side, like a product spec sheet. There is no header row there to group.
You get one thead per table. It can hold several rows, though, for example group titles above column titles. The caption does not go in it: caption has to be the first child of the table element itself.
Live example
Edit the code and watch the preview.
<table>
<thead>
<tr>
<th scope="col">Item</th>
<th scope="col">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tea</td>
<td>$2</td>
</tr>
</tbody>
</table>More examples
Two header rows
Home and away results mean two header rows. Row one names the column groups with scope="colgroup". Row two names the individual columns, and the Team header spans both. All of it lives in a single thead.
<table>
<colgroup span="1"></colgroup>
<colgroup span="2"></colgroup>
<colgroup span="2"></colgroup>
<thead>
<tr>
<th scope="col" rowspan="2">Team</th>
<th scope="colgroup" colspan="2">Home</th>
<th scope="colgroup" colspan="2">Away</th>
</tr>
<tr>
<th scope="col">Won</th>
<th scope="col">Lost</th>
<th scope="col">Won</th>
<th scope="col">Lost</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Lions</th>
<td>5</td>
<td>1</td>
<td>3</td>
<td>2</td>
</tr>
<tr>
<th scope="row">Owls</th>
<td>4</td>
<td>2</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>Sticky header in a scrolling box
Here the table lives in a short scrolling box. Its thead cells have position:sticky, and the column names stay pinned to the top as the rows move underneath. Scroll inside the box in the preview to try it.
<style>
.scroll{max-height:9em;overflow:auto;border:1px solid #ccc}
thead th{position:sticky;top:0;background:#fff}
</style>
<div class="scroll">
<table>
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col">Steps</th>
</tr>
</thead>
<tbody>
<tr><td>1 May</td><td>8,120</td></tr>
<tr><td>2 May</td><td>6,450</td></tr>
<tr><td>3 May</td><td>10,300</td></tr>
<tr><td>4 May</td><td>7,780</td></tr>
<tr><td>5 May</td><td>9,015</td></tr>
<tr><td>6 May</td><td>4,230</td></tr>
<tr><td>7 May</td><td>11,640</td></tr>
<tr><td>8 May</td><td>8,900</td></tr>
</tbody>
</table>
</div>Tip: Cells in thead still need to be th.
Browser support
All browsers handle thead, and the HTML Living Standard defines it. For sticky headers you need CSS position:sticky, which current browsers apply to <th> cells (details in CSS position:sticky support (opens in a new tab)). The big desktop browsers repeat the header on each printed page. Check a print preview anyway before a report depends on it.
Accessibility
Pair thead with th scope="col" and screen readers will announce the column header for every data cell. The pattern is shown in the W3C tutorial on tables with one header (opens in a new tab).
Common mistakes
Wrong
<thead>
<tr><td>Name</td><td>Price</td></tr>
</thead>Right
<thead>
<tr><th scope="col">Name</th><th scope="col">Price</th></tr>
</thead>Putting cells in thead does not make them headers. Use th.
Frequently asked questions
Is thead required in a table?
Does thead make cells into headers?
No. A row in <thead> still needs <th> cells before screen readers will treat them as headers; thead only groups rows. Each table gets at most one thead, placed after caption and colgroup and before tbody and tr elements.