Tables in accessibility

Associated themes :

General presentation #

A table is an arrangement of information in rows and columns containing cells that make it easy to compare and highlight information. They allow tabular information to be presented in a two-dimensional grid, such data is easier to read in tabular form.

This allows a user, who does not have a vision problem, to quickly make visual associations between table data and its table headings.

However, a blind user will not have access to all these relations between the information, it's the reason why it is important that the tables are implemented with the appropriate HTML markup so that they are the most accessible possible for assistive technologies.

In the rest of this article, we will see the main rules to follow to obtain an accessible table.

Add a caption/title to your table #

It is important to define a title for your table. Concise and relevant, this text will indicate its content as well as the type of data it contains.
It must be associated with the table using the caption element and must be the first element after the opening table tag. You can also use a h1,h2... title placed in the code just before the table as another way to associate a title.

Example caption #

    <caption>Time planning 2022</caption>

Example HTML title #

<h2>Time planning 2022</h2>

Add a description for complex table #

If you have a complex table and want to provide a more detailed summary, it is recommended to use the ARIA aria-describedby attribute.
It will programmatically link a description to your table.

<p id="info-table">
example of description to help understanding complex table

<table aria-describedby="info-table">
    <caption>Time planning 2022</caption>

There is also the possibility of using the summary attribute to give, in addition, a summary of the contents of a table, however this attribute is no longer part of the HTML 5 specifications and we do not recommend its use.

Identify your table headers #

Scope attribute #

To help assistive technology users, you must identify table headings, whether for rows or columns.
To identify these table headers, you must use the th tag, which must never be empty.

Once the headers are created, the data cells must be associated with the headers on which they rely.
The scope attribute allows cells to be programmatically linked to headers, and therefore, for assistive technologies, to identify them.

  • <th scope="col"> for a column header
  • <th scope="row"> for a row header

Id and header attributes #

Some tables are too complex to identify a strict horizontal or vertical association (for example, merged columns or rows) between the header and the data cells.
The scope attribute does not solve this problem. A unique id attribute must be used for each header cell. To link this header to a cell, you must use the headers attribute and adding the required id.

For example, we have two header cells, <th id="toto">Toto</th> and <th id="tata">Tata</ th>, the code to link it to a data cell will be <td headers="toto tata">Tota</td>.

Tables should use headers/id only if:

  • The table has column/row headings that change within the table.
  • A data cell with three or more related headers (often linked to header cells that are merged)

Creating accessible tables will allow consistent reading of these tabular data with a screen reader. To navigate in a table with Jaws or NVDA, there are several specific shortcuts.


To quickly navigate from table to table in a page, just use the t key, if you use the Shift + t shortcut, you navigate in the opposite direction and so we return to the previous table.

Once inside a table, there are several shortcuts to move around easily.

  • Ctrl + alt + left arrow moves to the left column while keeping the same line, Ctrl + alt + right arrow moves to the column right.
  • Ctrl + alt + down arrow moves to the next line while staying on the same column, Ctrl + alt + up arrow moves to the previous line.

Jaws #

For Jaws, you have to use the Y key and Shift + Y to navigate between tables.
To browse in tables, there are several shortcuts:

  • Insert + Ctrl + t lists all tables
  • Ctrl + alt + left arrow moves to the left column while keeping the same line, Ctrl + alt + right arrow moves to the column right.
  • Ctrl + alt + down arrow moves to the next line while staying on the same column, Ctrl + alt + up arrow moves to the previous line.
  • Insert + shift + up arrow reads the entire line.
  • Insert + shift + num pad 5 reads the entire column.

Table example #

We will now show you examples of accessible tables.

Simple table #

The first example is a table with only headers on the columns, so we use the scope="row" attribute for assistive technologies to interpret it correctly.

People with their professional activity
First name Name Gender Profession
John Doe M Unknown
Marty McFly M Guitarist
Ellen Ripley F Astronaut
Indiana Jones M Archaeologist
Sarah Connors F Waitress

<table class="table">
 <caption class="h4"> Personnes avec leur activité professionnelle</caption>
    <th scope="col">First name</th>
    <th scope="col">Name</th>
    <th scope="col">Genre</th>
    <th scope="col">Métier</th>

Like this, it is possible to easily navigate within the table using a screen reader. Also, any cell change from one column, or row, to another, the header will be vocalized.

For example, if we are positioned on the First name column, and we use the shortcut Ctrl+alt+right arrow to go to the Last name column, NVDA vocalizes "Last Name Column 2 + column text ".

Tables with Two Headers #

In this second example, the table is a planning time allowing you to quickly know whether the store is open or not, depending on the day of the week and the time.

This table requires two headers, one for the days of the week and another for the time slot.

Toy store opening
Monday Tuesday Wednesday Thursday Friday
09:00 - 11:00 Closed Open Open Open Closed
11:00 - 13:00 Open Open Open Open Closed
13:00 - 15:00 Open Open Closed Open Open
15:00 - 17:00 Open Open Closed Open Open

<table class="table">
  <caption class="h4">Toy Store Opening</caption>
     <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>
     <th scope="row">09:00 - 11:00</th>

Complex table #

In this example, some given cells have three associated headers, so we have to use the id and headers attributes.

Since the table is complex, we can add a description to help users understand the table.

Tables for calculating the compliance rate of a website.
For each page the criteria can be compliant, non-compliant or not applicable, and have two levels of difficulty: Beginner or advanced

Summary by level
Criteria Compliant Non-Compliant Non applicables Compliance rate
Level Beginner Confirmed Beginner Confirmed Beginner Confirmed
Home 17 13 0 0 13 7 100%
Article 17 12 0 1 13 7 97%

<p class="border-top border-light" id="tblDesc">Description of the table</p>
<table aria-describedby="tblDesc" class="table">
 <caption class="visually-hidden position-relative">Summary by level</caption>
    <th id="critere">Criteria</th>
    <th id="conforme" headers="critere" colspan="2">Compliant</th>
    <th id="niveau">Level</th>
    <th id="debutant-conforme" headers="niveau conforme">Beginner</th>
    <th id="confirme-conforme" headers="niveau conforme">Confirmed</th>
    <th id="accueil">Home</th>
    <td headers="accueil conforme debutant-conforme">17</td>
    <td headers="accueil conforme confirme-conforme">13</td>