Accessible Tables

HTML tables on the web come in two varieties, layout tables and data tables.

There is no question that the vast majority of tables on the web are layout tables, used to structure the visual appearance of the page. Often the structure of tables is remarkably complex, with tables nested in tables as much as seven deep.

In the Navigation section (Section 4) of this tutorial we talked a little bit about how tables are read, or linearized, independently of how complex those tables are. At least the definition of the linearization algorithm is simple. Lay out the text a line at a time starting with the first cell of the first row; then move across the columns of the first row, then proceed to the second row, and so on. If you come to a table in that process, linearize it and then continue. Another description of linearzation is "source code order." If you look at the source code of a page, and remove all the table tags (<table>, <tr>, <td> <th>, etc.) then the resulting text is the linearized version of the table. Finally, if you want an easy technique to see the way tables are spoken, look at a site that uses tables for layout, and apply the Linearize function in the Tables menu of the web Accessibility Toolbar (Section 3).

You should make sure that your pages make sense when linearized in this fashion. As we discussed in Section 3, one of the simplest views of your page in linear form is provided by the "lynx view," a rendering of the page as if you were using the Lynx text browser. This Delorie software Lynx Viewer site,, provides you the opportunity of seeing your page as if the browser were Lynx. Or you can use the Web Accessibility Toolbar (see Section 3), Check > Lynx Viewer. Usually the page will make sense.

Unless, that is, one or more of your tables is really a data table, because, while layout tables usually linearize well, data tables do not.

So what are data tables? How are they distinguished from layout tables? Data tables present things like financial results, rainfall totals by city and month, TV listings or bus schedules. What do these have in common? What is common is that the meaning of data in most cells of the table depends on heading information, which is usually in the first row and the first column of the table. You cannot know what the data means unless you are aware of the contents of the corresponding headings.

For layout tables, information in various cells stands on its own. There are no headings— just table cells containing text and images. In contrast, headings are crucially important for understanding (or reading) data tables. That is the problem! Your tables must be designed and marked up in such a way as to ensure that assistive technology will know where the headings are and be able to announce them.

Think of a TV listing -- for example, TV Guide (

Screen Shot of TV listings
Screen shot of TV listings

Here is part of the text view of this table from IBM Home Page Reader, starting at the time indicator (and Heading), 7:30:

7:30 PM
8:00 PM
8:30 PM
American Juniors
Paradise Hotel
George Lopez (Repeat)
Drew Carey
Drew Carey
Dating Experiment>
Law & Order (Repeat)
<60 Minutes II
Perfect Murder, Perfect Town (Repeat)
<Information Channel
Information Channel
<24 Hour Jewelry Celebration
24 Hour Jewelry Celebration
<Ken Burns American Stories (Repeat)
West Point (Repeat)
10 TBN
International Intelligence Briefing
Gaither Homecoming
Jack Van Impe Presents

When you read this, you will find that important information, represented by the tabular structure, is lost. Because of spanned cells, there is no way to even guess the time slot for a program, even if you did remember the headings. Imagine searching for a program title and then trying to figure out at what time and on what channel it will be aired. Nearly impossible!

This financial data table from ( has similar problems. Just imagine starting to read this table in the middle. It is hard enough to remember the column headings, let alone keep track of them as you view numeric data one cell at a time.

Remember that visually you can quickly glance at row and column headers to understand a piece of data; you can't do that when you are reading the table linearly.

screen shot of financial table
Financial data

There are a number of constructs in HTML 4.0 that contribute to making data tables accessible, that contribute to making it possible or listen to and understand a table. These are thoroughly discussed in the Tables section of the HTML 4.0 document,

We will discuss the three most important techniques for giving assistance to those with disabilities who are trying to interpret tabular information.

Using the caption element and the summary attribute

If you can see web page and you come across a data table, you naturally and automatically scan that table to get a quick sense of what the table presents. But some users have difficulty making that analysis, or simply cannot because they listen to the contents of the display rather than look at it. There are two techniques to help those users.

The caption element provides the web developer with a standard way of programmatically associating the title of the table with the table itself. The caption can appear at the top or bottom of the table. Even such a simple label can help orient a user to table content. And having it programmatically attached to the table means that screen readers will announce that as the table is encountered.

Today's Lunch Menu

Salad Entree Dessert
Caesar Chicken Divan Chocolate Mousse

A simple table with a caption

The simple table above has a caption, "Today's Lunch Menu," which explains the table contents. After hearing this caption, reading the three heading cells and three data cells would make (more) sense.

The following is the code for that table. Note the caption element directly after the table element. To move the caption to the bottom of the table, place the caption element just before the end table tag (</table>).

<table border="1" cellpadding="0" >
<caption>Today's Lunch Menu</caption>
<td>Caesar </td>
<td>Chicken Divan</td>
<td>Chocolate Mousse</td>

Because we know how assistive technology reads a table, we also know that this table would be organized better with its headings down a column, like this:

Today's Lunch Menu

Salad Caesar
Entree Chicken Divan
Dessert Chocolate Mousse

Lunch menu reads better

It then would read naturally (thanks to Home Page Reader):

Today's Lunch Menu
Salad Caesar
Entree Chicken Divan
Dessert Chocolate Mousse

When a table is more complicated, web authors are encouraged to use the summary attribute of the table element. This, like the longdesc attribute for images, is not represented visually. It is rendered from the HTML code by assistive technology like screen readers and talking browsers.

The summary attribute should contain a summary of the way the table is laid out - not a summary of the results. It should provide an orientation for someone who listens to the table.

Oceana Airlines Dinner Service

Class of Service Appetizer Salad Wine Entree Dessert
Economy Peanuts None Complimentary Soft Drinks, Liquor for Purchase Ham and Cheese Sandwich Packaged Cookies
Business Shrimp Cocktail Mixed Greens Oceana Label Chardonnay or Merlot Chicken Satay or Beef Tips New York Style Cheesecake
First Beluga Caviar Caesar, Salad Nicoise, or Antipasto Vive Clicquot Vintage Reserve 1990 Salmon Basil Cream, Raspberry Balsamic Chicken, Boeuf En Daube Assorted Belgian Truffles

Oceana Airlines dinner service

For this Dinner Service table the table element with its summary attribute looks like this.

<table border=1
summary="This table of Oceana Airlines dinner service gives 
	the five dinner courses (column headings) 
	for each class of service, Economy, Business, and First (row headings)">

With that summary, a person who is using a screen reader will have an overview of the table layout before he starts to read it.

Using Column and Row Headers

The techniques for dealing with data tables that we discussed so far are designed to give an overview of the table. These are not required by the Section 508 Standards. The next two techniques deal with the internals of the table. These techniques will enable you to satisfy the following two Section 508 Standards:

§1194.22 (g)
Row and column headers shall be identified for data tables.

§11924.22 (h)
Markup shall be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers.

Let's look first at §1194.22(g) that requires that you, in effect, label table headers as html headers (th) - not unlike what we talked about in the Navigation Section (Section 4) where heading text should be marked up as HTML headings (h1, h2, etc).

Each table cell is either a pure data cell (td) or a header cell (th). By default, headers will appear centered in bold so that most users can easily identify them. If this is not exactly the way you want your headers to appear, you can modify their appearance using style sheets (see Section 11). By labeling a cell as a th, you are identifying it as a table header as required by §1194.22 (g).

In addition to making the headers stand out, they can be identified by assistive technology so that when a talking browser is reading a specific cell it can, on command, search for the header cells and announce them. In addition, as the user moves from cell to cell, the assistive technology will announce the row and column headers that have changed. For example, moving across the Business class row in the Oceana Airlines Dinner Service table above, a screen reader user would hear, "Appetizer, Shrimp Cocktail, Salad, Mixed Greens, Wine, Oceana Label Cardonnay or Merlot, Entree, Chicken Satay or Beef Tips, Desert New York Style Cheesecake."

Both the Lunch Menu table and the Oceana Dinner Service table above have headers specified as they should be. You can see those headers (th) in the HTML code for the Lunch Menu Table. You can also use the Web Accessibility Toolbar, Tables > Table headers; this will put a black background on all cells which are table header cells (th).

The Oceana Dinner Service table is a little different because of the ambiguity of whether the top left cell is a header for its column or its row. This is resolved using the scope attribute on that th cell, or, as is recommended by many, on every th cell. The possibilities are scope="col" (which is appropriate for that top left cell) or scope="row". Here is the code for the first two rows of the Dinner Service table.

<th scope="col">Class of Service</th>
<td>Complimentary Soft Drinks, Liquor for Purchase</td>
<td>Ham and Cheese Sandwich</td>
<td>Packaged Cookies</td>

The coding for this table has evolved since it first appeared in Mike Paciello's book (Paciello, Michael G., Web Accessibility for People with Disabilities, Lawrence, Kansas: CMP Books, 2000); Mike used headers/id markup (more about that later) which is not necessary. The earlier version of this course included the scope attribute on all cells, not just the one cell whose scope is ambiguous. When you are using th cells, assistive technology knows they are headers and can deduce the scope; so the extra scope attributes are not necessary.

With the table marked up this way, a screen reader would announce the cells in the second row something like this: "Appetizer, Peanuts; Salad, None;" etc.

Alternative to using header cells (th) with the scope to resolve ambiguity, you can use data cells (td) with the scope attribute on any cell that is a heading. This technique has the advantage that you don't have to go back and restyle the heading text. Any cell is a heading if it is a th or it is a td with a scope attribute.

Using the headers Attribute

The final technique for making tables accessible is the most rigorous and programmatic. HTML 4.0 introduced the headers attribute for table cells. With the headers attribute you can specify any other cell or cells as the heading information for a given (data) cell.

The idea is simple. You attach an id attribute to any cell you want to be a header cell. Then, add the id's of each header cell to the headers attribute of a data cell.

For a simple case, let's say the id's of the column headers are c1, c2, c3, and c4 and the id's of the row headers are r1, r2, r3, and r4. Then the cell at row 3, column 2 would have headers="r3 c2" or the other way around, headers="c2 r3" if that sounded better.

In the "rectangular examples" above, assistive technology can figure out which is the header information. But in a table like the Travel Expense Report that follows, that is nearly impossible. (This table is from the Web Accessibility Initiative, Techniques for Web Content Accessibility Guidelines 1.0 ( - tables are discussed in Section 5 of that techniques document.)

Travel Expense Report

Meals Hotels Transport subtotals
San Jose
25-Aug-97 37.74 112.00 45.00
26-Aug-97 27.28 112.00 45.00
subtotals 65.02 224.00 90.00 379.02
27-Aug-97 96.25 109.00 36.00
28-Aug-97 35.00 109.00 36.00
subtotals 131.25 218.00 72.00 421.25
Totals 196.27 442.00 162.00 800.27

Complex table

Here is sample HTML mark up for the data cells of this table using the headers attribute. I have used the convention that c1, c2, c3, ... are the id's of the column headings and r1, r2, r3, ... are the id's of the row headings.

<table border="1">
<caption>Travel Expense Report</caption>
<tr> <td></td>
<th id="c2">Meals</th>
<th id="c3">Hotels</th>
<th id="c4">Transport</th>
<td id="c5">subtotals</td></tr>
<tr> <th id="r2">San Jose</th>
<td></td><td></td><td></td><td></td>  </tr>
<tr> <td id="r3" >25-Aug-97</td>
<td headers="c2 r2 r3" bgcolor="#ffff00">37.74</td>
<td headers="c3 r2 r3">112.00</td>
<td headers="c4 r2 r3">45.00</td>
<tr> <td id="r4">26-Aug-97
<td headers="c2 r2 r4">27.28</td>
<td headers="c3 r2 r4">112.00</td>
<td headers="c4 r2 r4">45.00</td>
<tr><th id="r10">Totals</th>
<td headers="c2 r10">196.27</td>
<td headers="c3 r10">442.00</td>
<td headers="c4 r10">162.00</td>
<td headers="c5 r10">800.27</td></tr>

The highlighted cell with the value 37.74, for example, is associated with the date "25-Aug-97" (id="r3"), the city "San Jose," (id="r2") and expense item "Meals" (id="c2"). To make it readable, the subject cell is coded:

<td headers="c2 r2 r3">37.74</td>

Assistive technology might then read this cell "Meals, San Jose, 25-Aug-97, 37.74" or "37.74 ,Meals, San Jose, 25-Aug-97."


In terms of money and workload, implementing accessible tables can be an expensive proposition. That expense can be reduced with careful design of data tables. If a table with 10 rows and 10 columns requires headers/id markup then all 100 cells must be specially coded. For simple tables, about 18 cells need special attention and what is done is repetitive which it is not true for the headers/id case.

Here is a summary of the techniques for accessible tables:

  • Use caption element as a title for the data table and and/or use the summary attribute to give a brief overview of the structure of the table.
  • And markup all table header cells
    • Use the table header element, th, for all header cells and add the scope attribute when that scope is ambiguous (corners).
    • Or use td together with the scope to specify header cells
    • Or use id attributes on the header cells and the headers attribute on the data cells to explicitly associate header information with data cells. This is essential if there are data cells whose header information is not in the same row and the same column as that cell.
  • And do not use any of the accessible data table markup (th, scope, headers, caption or summary) on a table used for layout. In particular, avoid gratuitous announcements resulting from summary="This table used for layout"

If you have comments or questions on the content of this course, please contact Jim Thatcher.

This course was originally written for the Information Technology Technical Assistance and Training Center, funded in support of Section 508 by NIDRR and GSA at Georgia Institute of Technology, Center for Rehabilitation Technology. The course has been completely revised.

Skip Sidebar.

Sections in this tutorial

Popular Pages