Tables with two headers

This page covers tables that have a simple row header and a simple column header. In such tables, the relationship between the headers and data cells becomes quickly ambiguous. For such tables, use the <th> element to identify the header cells and the scope attribute to declare the direction of each header. The scope attribute can be set to row or col to denote that a header applies to the entire row or column, respectively.

Additionally, you can use the <caption> element to identify the table in a document. This is particularly useful for screen-reader users browsing the web page in “table mode” where they can navigate from table to table. More background and guidance on the using <caption> element is provided on the Caption & Summary page.

Table with header cells in the top row and first column

The following table of opening times has header information in both the top row and the first column. All header cells are marked up as <th> cells with scope attributes added.

In the header row, the col value for scope associates each header cell with the data cells in the column. In the header column, the row value associates the individual headers with their rows. Without this information, some users would not easily understand the relationship between header and data cells. In the example below, the “Open” and “Closed” labels are only useful if they can be assigned to a particular day and time.

Example:
Delivery slots:
Monday Tuesday Wednesday Thursday Friday
09:00 - 11:00 Closed Open Open Closed Closed
11:00 - 13:00 Open Open Closed Closed Closed
13:00 - 15:00 Open Open Open Closed Closed
15:00 - 17:00 Closed Closed Closed Open Open
Code snippet:
<table>
  <caption>Delivery slots:</caption>
  <tr>
    <td></td>
    <th scope="col">Monday</th>
    <th scope="col">Tuesday</th>
    <th scope="col">Wednesday</th>
    <th scope="col">Thursday</th>
    <th scope="col">Friday</th>
  </tr>
  <tr>
    <th scope="row">09:00 - 11:00</th>
    <td>Closed</td>
    <td>Open</td>
    <td>Open</td>
    <td>Closed</td>
    <td>Closed</td>
  </tr>
  <tr>
    <th scope="row">11:00 - 13:00</th>
    <td>Open</td>
    <td>Open</td>
    <td>Closed</td>
    <td>Closed</td>
    <td>Closed</td>
  </tr>
  […]
</table>

Full code for “Table with header cells in the top row and first column”

Table with an offset column of header cells

In this table, the row header cells are in the second rather than in the first column. The approach is similar to the examples above: The scope of the header cells in the top row is set to col. By using the row value for scope assigns the header cells in the second column to the data cells on the left and the right of the individual header cell.

Example:
Holidays taken in the last six months
ID Name July August September October November December
215 Abel 5 2 0 0 0 3
231 Annette 0 5 3 0 0 6
173 Bernard 2 0 0 5 0 0
141 Gerald 0 10 0 0 0 8
99 Michael 8 8 8 8 0 4
Code snippet:
[…]
<tr>
  <td>215</td>
  <th scope="row">Abel</th>
  <td>5</td>
  <td>2</td>
  <td>0</td>
  <td>0</td>
  <td>0</td>
  <td>3</td>
</tr>
[…]

Full code for “Table with an offset column of header cells”

These tutorials provide best-practice guidance on implementing accessibility in different situations. This page combined the following WCAG 2.0 success criteria and techniques from different conformance levels:

Techniques: