Accessible xhtml tables 1: scope, id, headers

I haven’t had much call for creating hard core data table in my websites as most of the web work I do is promotional websites for companies in the tourism and leisure industry. However when asked to re-write some xhtml for an online bookings system I found some of the information generated seemed to lend itself to tabular organisation.

So I started to wonder if my limited knowledge of tables and table headers <th> was enough to make my tables accessible. Would I need to use <tbody> for instance. Is it necessary to use the scope attribute in the <th> element? What is the difference between a summary and a caption?

As it happened I decided that using a table for the data in question wasn’t the most semantic choice, but my appetite whetted, I thought I better brush up my table knowledge… just in case!

How do screen readers access tables?

Bim’s article on the RNIB website (Better Connected, Better Results: Table Headers) has got a great description of a screen reader user trying to navigate a table with no table header or <th> elements. Quite a task involving guessing which table cells hold the key heading information then trying to remember where you are the table and probably doing quite a bit of scrolling back and forth to work out what a particular piece of data represents.

She then goes on to explain how much easier it is when key information is coded as <th> instead of as <td>. When scrolling down a column, the row headers are announced together with the data. And to check which column you are in, instead of scrolling back to check, a keystroke will prompt Jaws to announce the column heading information. Although by default Jaws announces the row header and on a key stroke announces the column header, other screen readers may act differently.

So is <th> enough?


Do we need to include the attribute scope? I guess it would depend on the type and complexity of data you had to describe. If your table headers happened to be on the second row or second column for instance, it might be unclear as to which data the header described. With scope you can be certain.

What does the WCAG2 say about scope?

Scope can be an attribute of a table cell <td> or header <th>. Its values ‘row’ and ‘col’ (or ‘rowgroup’ and ‘colgroup’ see below) says whether the cell describes a row or a column.

Because the presence of the scope attribute implies the data in that cell is heading data, WCAG2 says you are allowed to use it in both data cells td or header cells th. However its suggested use is for data cells marked up with td that are actually header cells (although I’m not sure why you don’t just use th in this case … )

WCAG2 link: H63: Using the scope attribute to associate header cells and data cells in data tables

Note: The ‘rowgroup’ or ‘colgroup’ attributes are used to say if the header data describes groups of rows <thead>, <tfoot> and <tbody> element, or groups of columns <colgroup> element. See the w3c sample table, more info on rowgroup and more info on colgroup

Id, axis and header attributes

Scope isn’t consistently supported across screen reader technology apparently. So for more complex tables, a more robust alternative to scope is to use the ‘id’ attribute of a <th> and ‘headers’ attribute of a <td> to directly link a data cell to its header. The ‘axis’ attribute also allows you to give more information about your headers e.g time, location, weight, colour. It also allows you to style the table to make the info easier to understand.

Holistic healing work shop example

Dining Room Morning Room Blue Room The Orangery
Mon Flower arranging Origami Crystal healing Pottery
Tues Egg decorating Water colours Reflexology Yogurt weaving

<th id="dining" axis="venue">
Dining Room </th>
<th id="morning" axis="venue">
Morning Room </th>
<th id="blue" axis="venue">
Blue Room </th>
<th id="orange" axis="venue">
The Orangery </th></tr>
<th id="mon" axis="day">
Mon </th>
<td headers="dining mon">
Flower arranging </td>
<td headers="morning mon">
Origami </td>
<td headers="blue mon">
Crystal healing </td>
<td headers="orange mon">
Pottery </td>
<th id="tues" axis="day">
Tues </th>
<td headers="dining tues">
Egg decorating </td>
<td headers="morning tues">
Water colours </td>
<td headers="blue tues">
Reflexology </td>
<td headers="orange tues">
Yogurt weaving </td></tr>

What does the WCAG2 say?

If a table data cell has more than one header associated with it (e.g a row header and column header), it must have a headers attribute that lists all of the ids of the associated headers. Thus each header cell must have a unique id.

WCAG2 link: H43: Using id and headers attributes to associate data cells with header cells in data tables

Next up Captions and Summaries!