Tables

Accessible Tables

Data tables should not be used to force content into visible columns. This was a frequently abused technique in the past, but multi-column layouts can now be attained using CSS to handle layout and positioning.

That said, data tables are still useful for presenting data in rows and columns. A few specific HTML tags are required in order to ensure that data tables that are accessible to screen reader users. Without these tags, users who are unable to see the table can find it very difficult or impossible to understand the relationships between table headers and the cells within their scope.

The specific tags required depends on whether the table is simple or complex.

  • Simple tables can have two levels of headers. Each header cell should have scope="col" or scope="row".
  • Complex tables are tables with more than two levels of headers. Each header should be given a unique id and each data cell should have a headers attribute with each related header cell’s id listed.
  • When adding a title to a table, include it in a <caption> tag inside of the <table> element.

Usability

When to use

  • When you need tabular information, such as statistical data.

When to consider something else

  • Depending on the type of content, consider using other presentation formats such as definition lists or hierarchical lists.

Guidance

  • Tables are great at displaying tabular data. Minimal visual styling helps surface this information more easily.

Identify Row and Column Headers

A critical step toward creating an accessible data table is to designate row and/or column headers. In the markup, the <td> element is used for table data cells and the <th> element is used for table header cells. Going back to our original data table example, the column headers for this table are Name, Age, and Birthday. The row headers are Jackie and Beth. Also note the associated caption.

Shelly's Daughters
Name Age Birthday
Jackie 5 April 5
Beth 8 January 14

Table headers should never be empty. This is particularly of concern for the top-left cell of some tables

Associate the Data Cells with the Appropriate Headers

Now that we've created headers, we need to associate the data cells with the appropriate headers.

The scope attribute

The scope attribute identifies whether a table header is a column header or a row header. Here is the markup for the table, using the scope attribute:

<table>
<caption>Shelly's Daughters</caption>

<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">Birthday</th>
</tr>

<tr>
<th scope="row">Jackie</th>
<td>5</td>
<td>April 5</td>
</tr>

<tr>
<th scope="row">Beth</th>
<td>8</td>
<td>January 14</td>
</tr>

</table>

The scope attribute tells the browser and screen reader that everything within a column that is associated to the header with scope="col" in that column, and that a cell with scope="row" is a header for all cells in that row.

All <th> elements should generally always have a scope attribute. While screen readers may correctly guess whether a header is a column header or a row header based on the table layout, assigning a scope makes this unambiguous.

Scope will apply even if the table is complex with multiple levels of headers (such as in spanned cells). The scope of a table header will apply to all cells over which that header spans.

Shelly's Daughters
Name Age Birthday
by birth Jackie 5 April 5
Beth 8 January 14
by marriage Beth 8 January 14

In this example, the "by birth" row header has a scope of row, as do the headers with the names. The cell showing the age for Jackie will have 3 headers - one column header ("Age") and two row headers ("by birth" and "Jackie"). A screen reader would identify all of them, including the data cell content (e.g., it might read "by birth. Jackie. Age. 5.").

Note

Despite being standard markup for tables for many years, some screen readers still do not fully support complex tables with spanned or multiple levels of row and/or column headers. When possible, try to 'flatten' the table and avoid spanned cells and multiple levels of header cells.

The headers and id attributes

Another way to associate data cells and headers is to use the headers and id attributes. This method is NOT generally recommended because scope is usually sufficient for most tables, even if the table is complex with multiple levels of headers.

In extremely complex tables where scope may cause table headers to apply to (or have a scope for) cells that are not to be associated to that header, then headers and id may be used. In these cases, while headers and id might make the table technically accessible, if there are multiple levels of row and/or column headers being read, it will not likely be functionally accessible or understandable to a screen reader user.

With this approach, each <th> is assigned a unique id attribute value. Then, each and every <td> cell within the table is given a headers attribute with values that match each <th> id value the cell is associated to. The values are separated by spaces and should be listed in the order in which a screen reader should read them. If using headers/id in the example above, the cell for Jackie's age might be marked up as <td headers="birth jackie age">5</td>).

Again, it should be emphasized that this method is more complex, uses much more markup (and potential to become broken), and is rarely necessary (use scope instead).

Use Proportional Sizing, Rather than Absolute Sizing

The rule that applies to layout tables also applies to data tables. Let the browser window determine the width of the table whenever possible, to reduce the horizontal scrolling required of those with low vision. If cell widths need to be defined, use relative values, such a percentages, rather than pixel values. Defined cell heights should generally be avoided so the cell can expand downward to accommodate its content - something especially useful for users with low vision that may enlarge text content.

Other table markup

Summary

The summary attribute of the <table> tag may be used to provide a summary of a data table structure (not content). Support for summary varies, but in general, it is screen reader specific (it's not accessible to anyone else) and is not well supported. Additionally, the summary attribute is not part of the HTML5 specification. In general, if a table is so complex that it needs an explanation of how it is structured, it probably is not very accessible and should probably be simplified. For these reasons, we do not recommend the use of summary. If it is used, it must never be used for layout tables.

thead, tfoot, and tbody

The thead and tfoot elements define header and footer rows for tables. They provide no accessibility functionality and are generally only of use when a long table is printed - the head and/or foot rows will repeat at the top or bottom of each printed page. Similarly, the tbody element defines the body content of a data table (meaning anything that's not a thead or tfoot). Again, this element does not provide any additional accessibility benefit, but there is no harm in using it for table styling or other reasons.