Accessible Tables
What does a value in a table cell mean? Simply look at the header at the top of the column and/or somewhere at the beginning of the row. But what if you are blind?
When I talk about HTML tables, I don't mean how we used them for layout-purposes in the beginning of the internet. I only mean tabular data, where the table headers indicate what the meaning is of the data in the cell.
We have for instance this table from the Canine Research Center with some data about their dogs:
| Dog Name | Height (cm) | Length (cm) | Tail Length (cm) | Daily Food (kg) | Favorite Food | Bark Volume (dB) |
|---|---|---|---|---|---|---|
| Biscuit | 45 | 68 | 22 | 1.2 | Chicken & Rice | 85 |
| Max | 62 | 92 | 35 | 2.1 | Beef Stew | 95 |
| Jumbo | 320 | 600 | 150 | 150 | Hay & Vegetables | 117 |
| Mr. Whiskers | 25 | 45 | 28 | 0.3 | Tuna & Mice | 45 |
| Daisy | 35 | 52 | 19 | 0.8 | Lamb & Sweet Potato | 76 |
| Rocky | 58 | 85 | 32 | 1.8 | Raw Human Legs | 92 |
| Bella | 42 | 61 | 24 | 1.1 | Duck & Blueberry | 81 |
If you can see the screen, you see that Daisy’s tail length is 19 cm. An other row is an other dog. An other column is other data about that dog. If you don't know to what row or column a cell belongs, you only see data, but don't know what dog it is about and what it says about that dog. There has to be a connection between the cell and the headers.
scope attribute
Hundreds of millions cannot see a screen. Many visually impaired people have to read a webpage with a screen reader. A screen reader is software that reads the page aloud. If you do not relate the table cells to the headers, the screen reader would just read the values, which makes their meaning hard to understand.
So you have to associate the cells with the appropriate headers: the above value 19 is then read as: Daisy, tail length centimeter, 19.
To connect the headers with the columns and rows, you have to use the scope attribute in the table header (th) elements. On the top row in the above table the column headers look like this:
<thead>
<tr>
<th scope="col">Dog Name</th>
<th scope="col">Height (cm)</th>
<th scope="col">Length (cm)</th>
<th scope="col">Tail Length (cm)</th>
<th scope="col">Daily Food (kg)</th>
<th scope="col">Favorite Food</th>
<th scope="col">Bark Volume (dB)</th>
</tr>
</thead>
row headers
The names of the dogs in the above table are the row headers. To indicate that they are headers, you have to put them in a table header (th) element too, not a table data (td) element. With the scope attribute you can indicate that it is a header for a row. So Biscuit’s row in the above table is:
<tr>
<th scope="row">Biscuit</th>
<td>45</td>
<td>68</td>
<td>22</td>
<td>1.2</td>
<td>Chicken & Rice</td>
<td>85</td>
</tr>
In Joomla’s backend such a row header often is not in the first column. The list views in the Administrator side have a row header in the fifth or sixth column. Most of the time it is the column that refers to a form to edit the item. Also such a row header that is not in the first column should be a table header (th) element, with scope=”row”.
Only real headers should be a table header (th) element. For instance in Joomla’s backend list views the first cell is to select all checkboxes in the column beneath it. That is not a table header (th) element:
<td class="w-1 text-center">
<?php echo HTMLHelper::_('grid.checkall'); ?>
</td>
Cells that are not table header (th) elements should be table data (td) elements. For good accessibility a header (th) element should always have a scope attribute attached, to indicate if it is a header for the column or the row.
Joomla core is accessible
The above rules have been applied in Joomla CMS. The list views in the Administrator for instance all have the correct td and th elements, and all th elements have a scope attribute. Joohoo!
This article is mainly written to stimulate extension developers to also apply those rules. To make their extensions accessible. I didn’t find it in the documentation or tools for Joomla extension development (yet).
More complex tables
The scope attribute has two more possible values: ”colgroup” and “rowgroup”. With that you can assign headers to multiple columns or rows. Currently, that is not used anywhere in Joomla CMS. And that is good: the general advice is to avoid complex tables. If possible try to split them into multiple tables that are more simple.
With the scope attribute you connect the table headers with the columns and rows. The other way around is also possible: by adding a headers attribute to a table data (td) element. This is less used than the scope attribute in the table header (th) element, and should only be used in rare occasions when it is hardly possible to connect the cell and the header via the scope attribute. In Joomla CMS it is currently only used in /layouts/joomla/form/field/rules.php, although I suspect that we can easily apply scope=”col” there too, like in the rest of the CMS.
Sections
You should divide tables into three sections: thead, tbody, and tfooter. This structural division gives a better overview, styling possibilities, and is useful if you want to repeat headers and footers, for instance when printing multiple pages. But this division, although good practice, has no influence on how it is interpreted by screen readers.
Caption
A caption element is important for accessibility. It must be placed directly after the table tag. You can put relevant information there, what the table is about. And you can add information about filtering and ordering. In Joomla core that caption has a class="visually-hidden”. In Joomla core the (multilingual) caption for a table of articles looks like:
<caption class="visually-hidden">
<?php echo Text::_('COM_CONTENT_ARTICLES_TABLE_CAPTION'); ?>,
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
</caption>
Summary
In a HTML table:
- Check that all header cells are
thelements. Non header cells (that can also be in thetheadsection!) should betdelements. Don’t forget the row headers. - Check that all
thelements have ascopeattribute. - Check that all
scopeattributes have the valuerow,col,rowgroup, orcolgroup. Preferably onlyroworcol. - Put a
captionelement just under thetableelement.
Also see this WCAG-page about the scope attribute.
Some articles published on the Joomla Community Magazine represent the personal opinion or experience of the Author on the specific topic and might not be aligned to the official position of the Joomla Project
By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/
Comments