Accessibilty Tips

Tables and Accessibility

There are two types of tables: layout tables and data tables. Layout tables are used to visually organize content on a website and data tables are used to present data so column information is related to row information. Keep reading to find out more about accessibility techniques for all types of tables.

Layout Table Accessibility

Layout tables are used to organize the design and content of websites. Most websites use tables for layout purposes. Here are the main points to keep in mind

Content organization

text-based browsers and assistive technology read tables from left to right and top to bottom.

Avoid using data table markup

You should never use data table tags or attributes in layout tables because it's bad HTML code and confuses screen readers.

These are the tags and attributes you should avoid in layout tables

And for Optimal Accessibility

For best accessibility results websites would avoid using tables for layout purposes and instead use Cascading Style Sheets to control all design elements of a website. This option can be technically challenging for many web designers and it is not required for BCC websites.

Data Table Accessibility

Data tables organize data into a chart or spreadsheet in rows and columns. A data table is different from a layout table in that the column information presented is related to the row information.

When it comes to making data tables accessible, there are two types of data tables: simple and complex. A simple data table has up to one row of column headers and up to one column of row headers. A complex data table has two or more logical levels of row or column headers. Simple data tables are much simpler to make accessible. Because of this it is usually a good idea to simplify your tables when possible.

Example of a simple data table:

Name Phone Number Age Weight
Steve Nelson 425/555-2186 54 130 lbs.
Maria Sanchez 425/555-8741 43 120 lbs.

( Notice how the above table only has table headers on the top row.)

 

Example of a complex data table:

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

(Notice how the above table has multiple levels of column headers.)

 

Simple Data Tables

To make a simple data table accessible you need to make sure that table headers use at table header tag (<th>) on all table headers. Most WYSIWYG (what you see is what you get) HTML applications should allow you to easly make an html table cell a table header cell.

Example:

Name Phone Number Age Weight
Steve Nelson 425/555-2186 54 130 lbs.
Maria Sanchez 425/555-8741 43 120 lbs.

 

View HTML code:

<table width="80%" border="1" cellspacing="1"
cellpadding="2">

<tr> 
<th>Name</th>
<th>Phone Number</th>
<th>Age</th>
<th>Weight</th>
</tr>
<tr> 
<td>Steve Nelson</td>
<td>425/555-2186</td>
<td>54</td>
<td>130 lbs.</td>
</tr>
<tr> 
<td>Maria Sanchez</td>
<td>425/555-8741</td>
<td>43</td>
<td>120 lbs.</td>
</tr>
</table>

Notice how the table cells for the top row use the <th> tag instead of the <td> tag. This tells browsers that the contents of those table cells are table headers. In the above example it is acceptable to make the entire left column of table cells as table headers.

Complex Data Tables

Complex data tables are a little more cumbersome to make accessible and in most cases you will need to modify the HTML code to make these tables accessible. Like simple data tables, you still need to mark all table headers using the <th> tag. Since complex data tables have multiple levels of logical row or column headers, you need to use other HTML tags and attributes to associate table data with the different levels of table headers. There are multiple methods you can use to make complex data tables accessible, but this will depend on the data table or your personal preference.

HTML allows various ways to associate table content.

 

Using the scope attribute

One of the easiest ways of making your table accessible is through the use of the scope atribute. The scope attribute can associate rows, columns, row groups and column groups to a table cell.

The scope attribute can have four different values: "row", "col", "rowgroup" or "colgroup." By applying the value of 'row' to the scope attribute in a table header you associate all table cells in that row to the particular table header. By applying the value of 'col' to the scope attribute in a table header you associate all table cells in that column to the particular table header. On the table below you will notice how the scope attribute associate table cells to 2 different levels of column headers.

Example table using scope="col":

  Winter Summer
  Morning Afternoon Morning Afternoon
Wilma 9-11 12-6 7-11 12-3
Fred 10-11 12-6 9-11 12-5

 

View HTML code

<table>
<tr>
<th>&nbsp;</th>
<th colspan="2" scope="col" >Winter</th>
<th colspan="2" scope="col" >Summer</th>
</tr>

<tr>
<th>&nbsp;</th>
<th scope="col" >Morning</th>
<th scope="col" >Afternoon</th>
<th scope="col" >Morning</th>
<th scope="col" >Afternoon</th>
</tr>

<tr>
<td scope="row" >Wilma</td>
<td>9-11</td>
<td>12-6</td>
<td>7-11</td>
<td>12-3</td>
</tr>

<tr>
<td scope="row" >Fred</td>
<td>10-11</td>
<td>12-6</td>
<td>9-11</td>
<td>12-5</td>
</tr>

</table>

 

Scope vs. Headers and ID attributes

It is much easier to establish relationships between table cells and headers using the scope attribute.

Example of table using Scope attribute:

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

 

View HTML code

<table border="1" summary="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.">

<tr>
<th scope="col">Name</th>
<th scope="col">Cups</th>
<th scope="col" abbr="type">Type of Coffee</th>
<th scope="col">Sugar?</th>

<tr>
<td>T. Sexton</td>
<td>10</td>
<td>Espresso</td>
<td>No</td>

<tr>
<td>J. Dinnen</td>
<td>5</td>
<td>Decaf</td>
<td>Yes</td>

</table> 

 

Example of same table using headers and id attributes:

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

 

View HTML code

<table border="1" summary="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.">

<tr>
<th id="t1">Name</th>
<th id="t2">Cups</th>
<th id="t3" abbr="Type">Type of Coffee</th>
<th id="t4">Sugar?</th>
</tr>

<tr>
<td headers="t1">T. Sexton</td>
<td headers="t2">10</td>
<td headers="t3">Espresso</td>
<td headers="t4">No</td>
</tr>

<tr>
<td headers="t1">J. Dinnen</td>
<td headers="t2">5</td>
<td headers="t3">Decaf</td>
<td headers="t4">Yes</td>
</tr>

</table>

A speech synthesizer might render thes table as follows:

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.
Name: T. Sexton, Cups: 10, Type: Espresso, Sugar: No
Name: J. Dinnen, Cups: 5, Type: Decaf, Sugar: Yes

Note: how the header "Type of Coffee" is abbreviated to "Type" using the abbr attribute.

 

Using Axis for far more complicated tables

To create complex relationships between table cells, you will need to use the axis attribute along with the headers and id attributes

Example:

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

 

View HTML code

<table border="1">

<caption>
Travel Expense Report 
</caption>

<tr>
<th>
<th id="header2" axis="expenses">Meals 
<th id="header3" axis="expenses">Hotels 
<th id="header4" axis="expenses">Transport 
<td>subtotals</td>

<tr>
<th id="header6" axis="location">San Jose 
<th>
<th>
<th>
<td>

<tr>
<td id="header7" axis="date">25-Aug-97 
<td headers="header6 header7 header2">37.74 
<td headers="header6 header7 header3">112.00 
<td headers="header6 header7 header4">45.00 
<td> 
 
<tr> 
<td id="header8" axis="date">26-Aug-97 
<td headers="header6 header8 header2">27.28 
<td headers="header6 header8 header3">112.00 
<td headers="header6 header8 header4">45.00 
<td> 
         
<tr> 
<td>subtotals 
<td>65.02</td>
<td>224.00 
<td>90.00 
<td>379.02 
         
<tr> 
<th id="header10" axis="location">Seattle 
<th> 
<th> 
<th> 
<td> 
         
<tr> 
<td id="header11" axis="date">27-Aug-97 
<td headers="header10 header11 header2">96.25 
<td headers="header10 header11 header3">109.00 
<td headers="header10 header11 header4">36.00 
<td> 
         
<tr> 
<td id="header12" axis="date">28-Aug-97 
<td headers="header10 header12 header2">35.00 
<td headers="header10 header12 header3">109.00 
<td headers="header10 header12 header4">36.00 
<td> 
         
<tr> 
<td>subtotals 
<td>131.25 
<td>218.00 
<td>72.00 
<td>421.25 
         
<tr> 
<th>Totals 
<td>196.27 
<td>442.00 
<td>162.00 
<td>800.27 
         
</table>

A speech synthesizer might render it 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

More resources on data tables

Back to top