<th> Table header cell

Header cell for a column or row, shown bold and centered by default.

<th> marks a header cell. When a screen reader reads a data cell, it announces the headers that belong to it, so the table makes sense without seeing it.

Column headers take scope="col" and row headers take scope="row". With colspan and rowspan a header can stretch across several columns or rows. People often write a bold <td> where a th belongs; that cell is no header.

scope, headers and abbr are documented in the th element in the HTML Living Standard (opens in a new tab). Practise in the Headers and Captions lesson.

Syntax

<th scope="col">Column header</th>

When to use it

A cell that labels other cells is a <th>. Column titles in a price list, the names down the left of a comparison chart and the day names in a calendar are all headers. The test is simple enough: if the cell tells you what a column or row is about, it is a header.

Scope follows direction. Use col for a header above its data and row for one beside it. colgroup and rowgroup cover a group set up by colgroup or tbody. Long header text can get a short version in the abbr attribute, which some screen readers repeat in its place: "Avg days" for "Average delivery time in days".

The empty top-left corner of a two-way table labels nothing, so it is not a header. Make it a <td>. Left as an empty th, it can make some screen readers announce a blank header for that whole row or column. You can practise in the Headers and Captions lesson.

Attributes

AttributeWhat it does
scopecol, row, colgroup or rowgroup: which cells this header labels.
colspanNumber of columns the cell spans.
rowspanNumber of rows the cell spans.
headersIds of other header cells that label this cell.
abbrShort version of the header text.

Live example

Edit the code and watch the preview.

<table>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Score</th>
  </tr>
  <tr>
    <th scope="row">Ana</th>
    <td>92</td>
  </tr>
</table>

More examples

Two-way comparison table

Phones run across the top, features down the side. That gives the table column headers and row headers. The empty corner labels nothing, so it is a plain td.

<table>
  <tr>
    <td></td>
    <th scope="col">Phone A</th>
    <th scope="col">Phone B</th>
  </tr>
  <tr>
    <th scope="row">Battery</th>
    <td>4,500 mAh</td>
    <td>5,000 mAh</td>
  </tr>
  <tr>
    <th scope="row">Weight</th>
    <td>180 g</td>
    <td>205 g</td>
  </tr>
</table>

Region headers with rowgroup

Each region gets its own tbody. The region name is a header with scope="rowgroup" that spans the rows in its group. Shop names are row headers, each covering only its own line.

<table>
  <thead>
    <tr>
      <th scope="col">Region</th>
      <th scope="col">Shop</th>
      <th scope="col">Sales</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="rowgroup" rowspan="2">North</th>
      <th scope="row">Hilltop</th>
      <td>$4,200</td>
    </tr>
    <tr>
      <th scope="row">Riverside</th>
      <td>$3,100</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th scope="rowgroup" rowspan="2">South</th>
      <th scope="row">Harbour</th>
      <td>$5,600</td>
    </tr>
    <tr>
      <th scope="row">Old Town</th>
      <td>$2,900</td>
    </tr>
  </tbody>
</table>

Tip: Mark headers as th with scope, never bold td.

Browser support

th works in all browsers and is defined in the HTML Living Standard. The scope values col and row are well supported by screen readers. Colgroup, rowgroup and the abbr attribute are patchier. Keep complex tables as plain as the data allows, and run them through a screen reader if you get the chance.

Accessibility

Give every header cell a th with scope, and each data cell will be announced with its headers (WCAG 1.3.1). The W3C tutorial on tables with two headers (opens in a new tab) shows scope at work.

Common mistakes

Wrong

<td><b>Price</b></td>

Right

<th scope="col">Price</th>

Screen readers recognise th as a header. A bold td is only bold text.

Frequently asked questions

What does the scope attribute do on th?

It tells assistive technology which cells a header covers. scope can be col for the cells below, row for the cells to its right, or colgroup and rowgroup for groups. As the user moves through data cells, the screen reader announces the matching header. Browsers can guess for simple tables; an explicit scope is more reliable.

When do I need the headers attribute?

Only in complex tables, where a cell depends on several headers that scope cannot express. Give each <th> an id, then list the relevant ids in the cell's headers attribute, as in <td headers="q1 sales">. If you can, simplify the table or split it into smaller ones. The W3C has a worked example of tables with multi-level headers (opens in a new tab).

Practise it

Related tables elements