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
#
<table>
<caption>Time planning 2022</caption>
[...]
</table>
Example HTML title #
<h2>Time planning 2022</h2>
<table>
[...]
</table>
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
</p>
<table aria-describedby="info-table">
<caption>Time planning 2022</caption>
[...]
</table>
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)
Navigating a table using NVDA or JAWS #
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.
NVDA #
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.
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>
<tr>
<th scope="col">First name</th>
<th scope="col">Name</th>
<th scope="col">Genre</th>
<th scope="col">Métier</th>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>M</td>
<td>Inconnu</td>
</tr>
[...]
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.
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>
<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>
[...]
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
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>
<tr>
<th id="critere">Criteria</th>
<th id="conforme" headers="critere" colspan="2">Compliant</th>
[...]
</tr>
<tr>
<th id="niveau">Level</th>
<th id="debutant-conforme" headers="niveau conforme">Beginner</th>
<th id="confirme-conforme" headers="niveau conforme">Confirmed</th>
[...]
</tr>
<tr>
<th id="accueil">Home</th>
<td headers="accueil conforme debutant-conforme">17</td>
<td headers="accueil conforme confirme-conforme">13</td>
[...]
</tr>
[...]