One of the most common accessibility problems we find when conducting the Better Connected survey is the lack of marked up headers in data tables. So let’s look at why these are important, and how to make sure that tables can be clearly understood.
The importance of table headers
Data tables are a grid of pieces of information, few, (or none), of which are understandable in isolation. They’re displayed in a grid of columns and rows so that it’s easy to refer to the other pieces needed to make sense of the data.
Visually we do this by scanning the rows and columns to identify which holds the information we want, then we skip to the cell that contains the data. If we need reassurance that we’re in the right cell, a quick glance up and left will do the trick. We’ll initially recognise the key (header) cells by position, by a difference of text style or by making an instant decision about the importance or relevance of the data in potential key cells.
At the same time, our minds filter out the unwanted data in the cells between our “target” data and the key data. The combined data from the key and data cells should then make sense. It’s all done in the twinkling of an eye, and often we aren’t even conscious that we’re doing it, unless the table is huge and the cross-referencing requires effort.
Now, you probably knew all that anyway, but I’ve described the full process to underline the kind of things that we might take for granted:
- Locating potential key cells.
- Determining their importance at a glance.
- Skipping past or ignoring intervening data.
People who can’t see, obviously can’t do any of the above. Their screen readers may be able to do some of it, but they need markup to recognise the difference between data and key cells as the assumption that the top row and left-hand columns hold key information, isn’t safe.
Let’s look at an inaccessible example, (with no marked up headers):
Inaccessible example: 1. European pet ownership made up statistics
Imagine that you’re interested in how many people in France own cats, the data is in Column 6 of Row 4.
| Rank | Country | Population (millions) | Pet owners (millions) | Pet ownership | Cat owners (millions) | Cat ownership |
| 1 | UK | 60.36 | 21.8 | 36% | 10.2 | 17% |
| 2 | Greece | 11.33 | 3.9 | 34% | 2.2 | 19% |
| 3 | France | 61.36 | 20.3 | 33% | 7.9 | 13% |
This doesn’t seem too challenging, but screen readers don’t slide over data as easily as eyes do, they focus on, and announce, one cell at a time. Look at the steps that a JAWS user would need to perform, once the focus entered the table, to get the information that there were 7.9 million cat owners in France.
- Navigate across the top row to the Cat owners cell (5 depressions of the down arrow key), taking note en route that the Country data is in the second column.
- Navigate down the cat owners column (holding down CTRL and Alt, then depressing the down arrow key).
- Cross fingers that the headers have been marked up, as the Country info isn’t in the left hand column, so JAWS can’t be set to read top and left -most cells as titles. Query JAWS for the table titles (hold down Ctrl and Alt, then depress 5 on the number pad (right of the keyboard)).
- Hear "Cat owners (millions), 1, 10.2", because headers haven’t been coded.
- Navigate back to second column: (press up arrow 4 times), to locate the country (UK).
- Go down the Country column until "France" is heard, (down 2), and back to column 6, (4 cells to the right.
- Hear "7.9".
I’ve shortened steps 5 and 6, because you might otherwise have been driven crazy, but they require plenty of key depressions, and at each one that lands on an intervening cell, JAWS starts to announce the cell content, interrupted only by being moved on.
It really is hard work, and can so easily be avoided by marking up header cells properly.
Creating understandable tables
To distinguishe header, (key information), cells from data cells in a simple data table, use <th>, instead of <td>. That’s it, that’s all the web author has to do.
However, the person who creates the table needs to tell you which those key cells are. They know their own data, and are in the best position to decide which row and column needs to be referenced from a data cell to make sense of the table.
You’ll notice that in the example table above, the key information is in column 2. This can happen, visually it’s more logical to have the number or rank of an ordered list of rows in the left-hand column. But the rank, or order isn’t always, or often, the key information.
Let’s see an accessible version of the table.
Accessible example: 2.European pet ownership made up statistics
You still want the number of cat owners in France (Column 6, Row 4).
| Rank | Country | Population (millions) | Pet owners (millions) | Pet ownership | Cat owners (millions) | Cat ownership |
|---|---|---|---|---|---|---|
| 1 | UK | 60.36 | 21.8 | 36% | 10.2 | 17% |
| 2 | Greece | 11.33 | 3.9 | 34% | 2.2 | 19% |
| 3 | France | 61.36 | 20.3 | 33% | 7.9 | 13% |
Now the route to the information is so much easier for JAWS users:
- Navigate across the top row to the Cat owners cell (5 depressions of the down arrow key), taking note en route that the Country data is in the second column, not that it’s needed, but the user doesn’t know that yet.
- Navigate down the cat owners column (holding down CTRL and Alt, then depressing the down arrow key).
- Hear "UK, 10.2", because headers have been coded.
- Move down again and hear "Greece, 2.2".
- Move down again and hear "France, 7.9".
No unnecessary keystrokes, no audible output of a dozen or more intervening cells while trying to find key data. A much more equivalent browsing experience altogether.
And if the user wants reassurance that they’re in the desired column, querying the JAWS title announcement gives the audible output, "Cat owners (millions): France, 7.9". Nice!
Note: if the first column had been coded as header cells, or no left column cells had been marked up, the audible output would have been as unhelpful as the table without headers. JAWS would announce "Cat owners (millions): 3, 7.9".
So, two steps to making simple data tables simpler to understand:
- Get the table creator to identify the key information, (header), row and colum if it isn’t obvious.
- Code cells containing key information as header cells using <th>.
Thank you. :)
Ben 'Cerbera' Millard | 27/09/2007 at 13:30 | Permalink
I’ve mentioned this at Accessify Forum, in the thread about tables in HTML5. Do you find similar results in other screen readers?
Would it be useful if UAs could figure out which cells are headers even if they aren’t marked up with
<th>? Much like yourselves, the majority of tables I come across don’t use it (yet).Bim | 01/10/2007 at 8:31 | Permalink
I can’t say how other screen readers handle tables Ben. I’ve tried learning others but haven’t found enough time to master them. Perhaps other screen reader users could answer your first question.
I don’t think user agents could reliably choose which cells contain headers though. It’s a decision that needs to be based on knowledge, which is why I suggest that authors refer to the person who compiled the table, if the key information isn’t obvious.
Would the user agent “make decisions” based on the number of characters in the data cell, or position, for instance? These could be programmatically determined, but could so easily identify false “key” data and cause more confusion than they cure.
Ben 'Cerbera' Millard | 06/10/2007 at 20:21 | Permalink
My reply wouldn’t go through, so I’ve made it at How to Disarm an Inaccessible Data Table. Discussion should continue in these comments, since this is where the original article is.
Ben 'Cerbera' Millard | 09/10/2007 at 20:58 | Permalink
By the way, this is my favourite article about why users need table headers to be identified. Just the right amount of detail, aided by examples and step-by-step summaries.
Bim | 25/10/2007 at 11:24 | Permalink
Thanks for the kind words again Ben.
To answer the questions in your blog post :
Currently browsers do display this as bold text inside a table cell. However, screen readers don’t recognise styles. If this were to be used instead of <th>, it may be years beforea ll screen readers treated this as a header and all, or most, screen reader users had upgraded to the version that did support it. I’m also not sure how a screen reader would be able to tell the difference between an HTML 4 page using this just for styling and an HTML 5 page using it as headers.
Your other question:
Most of the time yes, the topmost row and left-hand column are the logical headers, but this is the point of this article. What happens when they aren’t? We can’t really expect the sighted world to change it’s natural order, so that the left-hand column always held the logical headers.
Hope I haven’t misunderstood the points you were making Ben, keep up the good work.
kral oyun | 06/12/2007 at 11:38 | Permalink
Would it be useful if UAs could figure out which cells are headers even if they aren’t marked up with ? Much like yourselves, the majority of tables I come across don’t use it (yet).