Menu

Accessible tables

On this page

Tables are widely used to show figures, data and their relationships, from annual accounts to product comparisons. With the right structure, they also work well for people using assistive technology such as screen readers.

The problems with tables

People often advise against complex tables, and with good reason.

The first, often hardest, problem is the cognitive effort needed to process the information. Some people find tables an excellent way to present a lot of information compactly. Others find them difficult and struggle to understand the overall picture.

The second problem is technical. To make table information understandable for people with visual disabilities, the table code needs the right structure. Only then can a screen reader extract all the information.

A screen reader user navigates through a table cell by cell. Each cell is read separately.

Without the right markup, there is no information about the row and column a cell belongs to. Its meaning may then be unclear.

Making tables accessible to people: reducing cognitive effort

This may be the hardest problem to solve.

First, consider whether you can present the information more simply. This makes it accessible to more people. Could you divide it into several smaller tables or use lists instead?

Simplifying is not always possible. There may be a legal obligation to publish information in a particular format. Another option is to provide the information as text alongside the table.

Making tables accessible to computers: solving the technical problem

Tables can be technically accessible even when they are complex. The implementation becomes more complex too, and not every CMS supports it.

A well-structured table uses the appropriate HTML elements:

  • table: the container for all the information.
  • caption: the table’s first child element. Use it for a brief description of the content and other relevant information. A screen reader announces it when arriving at the table.
  • tr: the container for each table row.
  • th: a table header that identifies the subject of a row or column.
  • td: a data cell containing information.

Implicit associations

HTML table elements have implicit associations. When the table is marked up correctly, relationships can be established automatically. A screen reader can determine which headers belong to each cell.

These implicit associations work well for simple tables in most screen readers.

Explicit associations

We can add attributes to create reliable programmatic relationships between data cells (td) and headers (th). These are explicit associations.

For more complex layouts, such as tables with merged cells using colspan or rowspan, it is advisable to define the associations yourself.

Defining scope

Add the scope attribute to make table associations more reliable. It identifies whether a header applies to a row or column.

Tip: this form of header association is sufficient for most tables, including many complex ones. Always test the table. If problems arise, first consider simplifying it before using more complex associations.

The scope attribute has these two values:

  • scope="col": the th element is a column header.
  • scope="row": the th element is a row header.

The code below shows a simple table with explicit associations using scope.

Skip: Example code for a swimming pool admission prices table
<table>
  <caption>entreekosten zwembad (in euro's)</caption>
  <tr>
    <td></td>
    <th scope="col">Los zwemmen</th>
    <th scope="col">10-baden kaart</th>
  </tr>
  <tr>
    <th scope="row">Vrij zwemmen</th>
    <td>5,25</td>
    <td>47,50</td>
  </tr>
  <tr>
    <th scope="row">Banen zwemmen</th>
    <td>4,50</td>
    <td>40,00</td>
  </tr>
</table>
Example code for a swimming pool admission prices table
Example code for a swimming pool admission prices table skipped

The id and headers attributes

Another way to define these relationships is through the id and headers attributes. This creates an association for each data cell (td).

Note: this method has a significant effect on the screen reader experience. It is also more complex and prone to implementation errors.

The screen reader reads the associated headers for every cell. As complexity increases, so does the amount announced. The table may be technically accessible but no longer practical to use.

First, give every table header (th) a unique id, such as <th id="c1">.

Then use these IDs in the data cells’ headers attributes. Combine them like this: <td headers="c1 r2">. Separate values with spaces; they are announced in the specified order.

The earlier code example looks like this with headers and id attributes:

Skip: Example swimming pool admission prices table using id and headers attributes
<table>
  <caption>entreekosten zwembad (in euro's)</caption>
  <tr>
    <td></td>
    <th id="c1">Los zwemmen</th>
    <th id="c2">10-baden kaart</th>
  </tr>
  <tr>
    <th id="r1">Vrij zwemmen</th>
    <td headers="c1 r1">5,25</td>
    <td headers="c2 r1">47,50</td>
  </tr>
  <tr>
    <th id="r2">Banen zwemmen</th>
    <td headers="c2 r1">4,50</td>
    <td headers="c2 r2">40,00</td>
  </tr>
</table>
Example swimming pool admission prices table using id and headers attributes
Example swimming pool admission prices table using id and headers attributes skipped

A screen reader now reads the associated th elements for each cell.

Help with accessible tables

Tables can be accessible when you pay attention to both the user and the technical implementation.

Bear in mind that most content management systems do not support these complex tables directly. They often need to be coded by hand.

Need support?

Would you like help creating accessible tables, or other editorial support with digital accessibility?