Creating accessible tables


Row and column headers

Row and column headers should be identified for data tables.

Tables used strictly for layout purposes should not have header rows or columns. Data tables should have column and row headers appropriately identified (using the <TH> tag)

Tables allow us to arrange data -- text, images, links, other tables, etc. -- into rows and columns of cells. Tables should not be used purely as a means to layout document content as this may present problems when rendering to non-visual media. Additionally, when used with graphics, these tables may force users to scroll horizontally to view a table designed on a system with a larger display. To minimize these problems, authors should use style sheets, not tables, to control layout.

Table cells may either contain "header" information (use the TH element) or "data" (see the TD element). Cells may span multiple rows and columns. Individual cells can be labeled to communicate heading information about the cell (see markup for cells in data tables below). This information greatly assists users with visual disabilities, and allows multi-modal wireless /preowsers with limited display capabilities (e.g., Web-enabled pagers and phones) to handle tables.

Each table may have an associated caption that provides a short description of the table's purpose: e.g., <CAPTION>text</CAPTION>. For a longer description, use the summary attribute of the Table Element: e.g.,<TABLE summary="text">

When using Dreamweaver, you can select Edit>Preferences>Accessibility and then choose the tables checkbox. When you create a table, the following dialog box will appear:

Accessibility Options for Tables dialog box

This dialog box includes caption and summary text input fields. It also allows you to automatically create header tags for all your rows and/or columns. The align attribute of the caption element, meanwhile, like all style related attributes, can be more efficiently set in a style sheet.

For more information, see the World Wide Web Consortium's table page, from which this explanation has been adapted. For a /preief example, see the table below:

<TABLE border="1" summary="This table charts the number of
cups of coffee consumed by each senator, the type of coffee
(decaf or regular), and whether taken with sugar.">
    <caption>Cups of coffee consumed by each senator</caption>
    <tr> 
        <th>Name</th>
        <th>Cups</th>
        <th>Type of Coffee</th>
        <th>Sugar?</th>
    </tr>
    <tr> 
        <th>T. Sexton</th>
        <td>10</td>
        <td>Espresso</td>
        <td>No</td>
    </tr>
    <tr>
        <th>J. Dinnen</th>
        <td>5</td>
        <td>Decaf</td>
        <td>Yes</td>
    </tr>
</table>
Cups of coffee consumed by each senator
Name Cups Type of Coffee Sugar?
T. Sexton 10 Espresso No
J. Dinnen 5 Decaf Yes

Markup for cells in data tables

Markup (html tags) should be used to associate data cells and header cells for data tables that have two or more logical levels of row or column headers

Table cells should be associated with the appropriate headers (i.e. with the id, headers, scope and/or axis HTML attributes

  • Headers (THEAD, TFOOT, and TBODY)
  • Scope
  • Axis

Headers
Use headers to identify relationships among table cells. Headers allow screen readers to interpret the information in tables. If there is more than one row or column of headers, a more extensive description of the relationship between cells helps the user understand the table's structure better.

Table rows may be grouped into head, foot, and body sections, with the THEAD, TFOOT and TBODY elements, respectively. These row groups convey additional structural information and may be rendered in ways that emphasize this structure. The head/body/foot division can help users scroll sections independently of the head and foot. When long tables are printed, the head and foot information may be repeated on each page that contains table data.

The table head and table foot should contain information about the table's columns. The table body should contain rows of table data. The following example illustrates the order and structure of table heads, feet, and bodies.

<TABLE>
  		<THEAD>
  		<TR> ...header information...
  		</THEAD>

  		<TFOOT>
  		<TR> ...footer information...
  		</TFOOT>
  		<TBODY>
  		<TR> ...first row of block one data...

  		<TR> ...second row of block one data...
  		</TBODY>
  		<TBODY>
  		<TR> ...first row of block two data...
  		<TR> ...second row of block two data...

  		<TR> ...third row of block two data...
  		</TBODY>
  		</TABLE> 

TFOOT must appear before TBODY within a TABLE definition.

Column groups can also provide additional structural information. Use the COLGROUP and COL elements to declare column properties at the start of a table definition. Users can then read the table incrementally rather than having to wait for all the table data to arrive.

Scope
The following example associates header and data information with the "scope" attribute rather than headers. Scope must have one of the following values: "row", "col", "rowgroup", or "colgroup." Scope specifies the set of data cells to be associated with the current header cell. This method is particularly useful for simple tables like the following:

Cups of coffee consumed by each senator

Name Cups Type of Coffee Sugar?
T. Sexton 10 Espresso No
J. Dinnen 5 Decaf Yes

Here is the HTML for the above table. Note the <TH> tags defining each column.

<TABLE border="border" summary="This table charts the number
  		of cups of coffee consumed by each senator, the type of coffee 
  		(decaf or regular), and whether taken with sugar.">
  		<CAPTION>Cups of coffee consumed by each senator</CAPTION>
  		<TR>
  		<TH scope="col">Name</TH>
  		<TH scope="col">Cups</TH>
  		<TH scope="col" ab/pre="Type">Type
  		of Coffee</TH>
  		<TH scope="col">Sugar?</TH>
  		</TR>
  		<TR>
		<TH scope="row">T. Sexton</TH>
  		<TD>10</TD>
  		<TD>Espresso</TD>
  		<TD>No</TD>
  		</TR>
  		<TR>
		<TH scope="row">J. Dinnen</TH>
  		<TD>5</TD>
  		<TD>Decaf</TD>
  		<TD>Yes</TD>
  		</TR>
  		</TABLE>

The axis tag can be used to create categories in more complex tables. Use it to group similar elements.

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
Seattle
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

A speech synthesizer might render the example above by speaking the following:

San Jose
  		25-Aug-97: Meals: 37.74, Hotels: 112.00, Transport: 45.00
  		26-Aug-97: Meals: 27.28, Hotels: 112.00, Transport: 45.00
  		subtotals: Meals: 65.02, Hotels: 224.00, Transport: 90.00, subtotals: 379.02
  		etc.

Alternatively, the user may be interested only in a particular column, and with the appropriate markup can instruct the speech synthesizer to read it as follows:

Meals
  		San Jose
  		25-Aug-97: 37.74
  		26-Aug-97: 27.28
  		subtotals: 65.02

  		Seattle
  		27-Aug-97: 96.25
  		28-Aug-97: 35.00
  		subtotals: 131.25
  		Totals: 196.24

The HTML source for this example follows. Notice how "axis", "headers", and "id" attributes are used in some of the TH and/or TD tags. The axis attribute creates categories of headers uniquely identified by the id attribute, and the headers attribute refers to all of the headers associated with a particular cell.

<TABLE border="border" summary="this complex table example summarizes travel
		  expenses incurred during August trips to San Jose and Seattle">
		  <CAPTION> Travel Expense Report </CAPTION>

		  <TR>
		  <TH></TH>
		  <TH id="e1" axis="expenses">Meals</TH>
		  <TH id="e2" axis="expenses">Hotels</TH>

		  <TH id="e3" axis="expenses">Transport</TH>
		  <TH id="s1" axis="subtotals">subtotals</TH>

		  </TR>
		  <TR>
		  <TH id="l1" axis="location">San Jose</TH>
		  </TR>

		  <TR>
		  <TD id="d1" axis="date">25-Aug-97</TD>
		  <TD headers="l1 d1 e1">37.74</TD>

		  <TD headers="l1 d1 e2">112.00</TD>
		  <TD headers="l1 d1 e3">45.00</TD>
		  <TD></TD>
		  </TR>

		  <TR>
		  <TD headers="l1" id="d2" axis="date">26-Aug-97</TD>
		  <TD headers="l1 d2 e1">27.28</TD>

		  <TD headers="l1 d2 e2">112.00</TD>
		  <TD headers="l1 d2 e3">45.00</TD>
		  <TD></TD>
		  </TR>

		  <TR>
		  <TH headers="l1"id="s2"axis="subtotals">subtotals</TH>
		  <TD headers="l1 s2 e1">65.02</TD>

		  <TD headers="l1 s2 e2">224.00</TD>
		  <TD headers="l1 s2 e3">90.00</TD>
		  <TD headers="l1 s2 s1">379.02</TD>

		  </TR>
		  <TR>
		  <TH id="l2" axis="location">Seattle</TH>
		  </TR>

		  <TR>
		  <TD headers="l2"id="d3" axis="date">27-Aug-97</TD>
		  <TD headers="l2 d3 e1">96.25</TD>

		  <TD headers="l2 d3 e2">109.00</TD>
		  <TD headers="l2 d3 e3">36.00</TD>
		  <TD></TD>
		  </TR>

		  <TR>
		  <TD headers="l2"id="d4" axis="date">28-Aug-97</TD>
		  <TD headers="l2 d4 e1">35.00</TD>

		  <TD headers="l2 d4 e2">109.00</TD>
		  <TD headers="l2 d4 e3">36.00</TD>
		  <TD></TD>
		  </TR>

		  <TR>
		  <TD headers="l2"id="s3" axis="subtotals">subtotals</TD>
		  <TD headers="l2 s3 e1">131.25</TD>

		  <TD headers="l2 s3 e2">218.00 
		  </TD>
		  <TD headers="l2 s3 e3">72.00</TD>
		  <TD headers="l2 s3 s1">421.25</TD>

		  </TR>
		  <TR>
		  <TH id="t1" axis="totals">Totals</TH>
		  <TD headers="t1 e1">196.27</TD>

		  <TD headers="t1 e2">442.00</TD>
		  <TD headers="t1 e3">162.00</TD>
		  <TD headers="t1 s1">800.27</TD>

		  </TR>
		  </TABLE> 

For more information, see the World Wide Web Consortium's table page, from which this explanation has been adapted.

Printer-friendly version