So tldr, use
<th> tags with a
scope attribute! If you're wondering what the
scope attribute is, welcome to my life circa 3 days ago and please read on.
Tables have been a core part of HTML for a long time. They were introduced with RFC 1942 back in 1996 and I've been doing them wrong ever since. Initially my markup only consisted of the bare minimum to get a table to display
<table> <tr> <td>Cereal</td> <td>Weight</td> <td>Cost</td> </tr> <tr> <td>Corn flakes</td> <td>450g</td> <td>77p</td> </tr> <tr> <td>Shreddies</td> <td>750g</td> <td>£1.10</td> </tr> </table>
Most developers will immediately spot there's a lot missing here, but this works so why would we need more? Because it makes everyone's lives easier including the developers. Consider wanting to style the above. If you wanted the header row to have different formatting your selector will end up more complicated than it needs to be. Queue the next stage in my table evolution.
<table> <thead> <tr> <th>Cereal</th> <th>Weight</th> <th>Cost</th> </tr> </thead> <tbody> <tr> <td>Corn flakes</td> <td>450g</td> <td>77p</td> </tr> <tr> <td>Shreddies</td> <td>750g</td> <td>£1.10</td> </tr> </tbody> </table>
So the header row has been wrapped in
<thead> tags, and the rest in
<tbody> (there's also the
<tfoot> tag if you need it), and the
<td>'s in the header have also changed to
<th>. This does a few things to makes life easier for us all.
As a developer using the
<tfoot> tags separates the parts of your table, which I find makes it easier for me to spot the part I need to be working on. For our users they can make it so that the browsers can freeze the header whilst scrolling the body.
<th> tag can now be used to style the header's easily as well as providing a vital role in making the tables more accessible. When reading the table with a screen reader the user can get the reader to read the cell headers wherever they are in the table, but there's still a problem. If the user selected the £1.10 cell it would only read "Price £1.10" without telling the user what it's the price of.
Fixing this requires two steps. Firstly, add a
scope attribute to the existing
<th>s with a value of "col". This unambiguously tells the screen reader that the header is for the cells in that column, and secondly we should change the row headers in to
<th> cells also with a
<table> <thead> <tr> <th scope="col">Cereal</th> <th scope="col">Weight</th> <th scope="col">Cost</th> </tr> </thead> <tbody> <tr> <th scope="row">Corn flakes</th> <td>450g</td> <td>77p</td> </tr> <tr> <th scope="row">Shreddies</th> <td>750g</td> <td>£1.10</td> </tr> </tbody> </table>
Now screen readers know that our £1.10 is the price for shreddies. Additional benefit is again for us developers as we can now style the row headers separately from the rest of the
<td>s in the row.
Last tip is to add a
<caption> tag to the table and then it'll be complete.
HTML is designed to be accessible for as many people as possible, but the language doesn't enforce it. This means that developers like me can go for more than 2 decades without realising some of these features exist. Please share any similar moments you've had in the comments.