Ensure that Each Cell In a Table That Uses the Headers Attribute Refers Only to Other Cells In That Table

Yotam Flohr
Researcher
Blind Hearing
WCAG 2.1 Level A

Written and researched for humans by humans

Yotam Flohr
Researcher
Ritvik Shrivastava
Expertly reviewed by
Comments: 0
Your entire domain
Get detailed instructions on how to resolve every accessibility issue on your website

Data table markup can be time-consuming and confusing. Tables should be marked up semantically and with the correct header structure.

Why It Matters

When tables are not marked up correctly it leads to confusing or inaccurate screen reader output.

When a data table is designed with accessibility in mind, a user is able to navigate from cell to cell within the table while hearing the screen reader announce the corresponding table headers for the data cells. 

Fixing the Issue

Developers should ensure that each cell in a table using headers refers to another cell in the same table by creating a scope attribute value on each th element within tr elements. This rule checks that references to header columns and rows connect to specific td elements.

Good Code Example

Code example
<table> <caption><strong>Greensprings Running Club Personal Bests</strong></caption> <thead> <tr> <th scope="col">Name</th> <th scope="col">1 mile</th> <th scope="col">5 km</th> <th scope="col">10 km</th> </tr> </thead><tbody> <tr> <th scope="row">Mary</th> <td>8:32</td> <td>28:04</td> <td>1:01:16</td> </tr><tr> <th scope="row">Betsy</th> <td>7:43</td> <td>26:47</td> <td>55:38</td> </tr><tr> <th scope="row">Matt</th> <td>7:55</td> <td>27:29</td> <td>57:04</td> </tr><tr> <th scope="row">Todd</th> <td>7:01</td> <td>24:21</td> <td>50:35</td> </tr> </tbody></table> Copy

Example including scope=”colgroup” and scope=”rowgroup” values on th elements:

Code example
<table> <caption>Items Sold August 2016</caption> <tbody> <tr> <td></td> <td></td> <th colspan="3" scope="colgroup">Clothes</th> <th colspan="2" scope="colgroup">Accessories</th> </tr> <tr> <td></td> <td></td> <th scope="col">Trousers</th> <th scope="col">Skirts</th> <th scope="col">Dresses</th> <th scope="col">Bracelets</th> <th scope="col">Rings</th> </tr> <tr> <th rowspan="3" scope="rowgroup">Belgium</th> <th scope="row">Antwerp</th> <td>56</td> <td>22</td> <td>43</td> <td>72</td> <td>23</td> </tr> <tr> <th scope="row">Gent</th> <td>46</td> <td>18</td> <td>50</td> <td>61</td> <td>15</td> </tr> <tr> <th scope="row">Brussels</th> <td>51</td> <td>27</td> <td>38</td> <td>69</td> <td>28</td> </tr> <tr> <th rowspan="2" scope="rowgroup">The Netherlands</th> <th scope="row">Amsterdam</th> <td>89</td> <td>34</td> <td>69</td> <td>85</td> <td>38</td> </tr> <tr> <th scope="row">Utrecht</th> <td>80</td> <td>12</td> <td>43</td> <td>36</td> <td>19</td> </tr> </tbody> </table> Copy

Test Cases

For more examples, visit the W3C’s GitHub’s ATC Rules library.