Jump to main content
Menu

Accessible Data Tables

Why Code for Accessibility?

  • Accessibility refers to making web content easy to access, understand, and use for people with disabilities.
  • Tables, if used for their intended purpose of presenting tabular data, present fewer difficulties for users experiencing a web page with non-visual software (e.g., screen reader).
  • These screen readers go through the tables row by row, moving through all the cells of the first <tr> before progressing to the next <tr> (a process called linearizing the table).
  • Difficulties are much more likely to arise when tables are used for page layout, as the content on the page can seem disjointed when read in a linear sequence of rows and cells.
  • Important considerations:
    • These tags and attributes are only to be used for data tables, not for tables used in page layout.
    • Keep in mind that assistive technology support for these will vary; all we can do is make the code as accessible as possible and hope that the user's assistive technology is supportive.
    • It is better for accessibility to use a properly marked up data table than to use non-table elements (such as divs) that are styled to look like a table, because assistive technology can more easily work with, and better communicate the values, in the data table.

Working with Column Headers

abbr attribute

  • The abbr (abbreviation) attribute can be placed inside <th>, so that as the heading is read aloud again and again (before the associated data cell's content) the abbreviation is read, not the full wording.
  • The goal is to reduce the amount of text being spoken / output, especially as it is repeated time and time again.

abbr Example

<table border="1">
<tr>
  <th abbr="first">First Name</th>
  <th abbr="last">Last Name</th>
  <th abbr="age">Years of Age</th>
</tr>
</table>

<thead>

  • Defines the row or rows that constitutes the head of the table.
  • Must contain at least one <tr> tag.
  • One of the few tags allowed to go between <table> and <tr>.
  • No visual effect on rendering.
  • There is only one <thead> per table.
  • Browsers will print the rows within <thead> at the top of each page, assuming that the table content wraps across a page or pages.

<thead> Example

<table border="1">
<thead>
<tr>
  <th abbr="first">First Name</th>
  <th abbr="last">Last Name</th>
  <th abbr="age">Years of Age</th>
</tr>
</thead>
</table>

Indicating Table Body and Footer

<tbody>

  • Defines a group of rows as the 'body' of the table, but note that there can be multiple sets of these per table (you can make multiple groups of rows, which has a variety of uses and benefits).
  • Must contain at least one <tr> tag.
  • One of the few tags allowed to go between </tr> and the next <tr> tag.
  • No visual effect on rendering.

<tbody> Example

<table border="1">
<thead>
<tr>
  <th abbr="first">First Name</th>
  <th abbr="last">Last Name</th>
  <th abbr="age">Years of Age</th>
</tr>
</thead>
<tbody>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
</tbody>
</table>

<tfoot>

  • Defines the foot of a table.
  • <tfoot> should contain information about a table's columns.
  • There is only one <tfoot> per table.
  • Must contain at least one <tr> tag.
  • One of the few tags allowed to go between </tr> and the next <tr> tag.
  • Browsers will print the rows within <tfoot> at the bottom of each page, assuming that the table content wraps across a page or pages.

<tfoot> Example

<table border="1">
<thead>
<tr>
  <th abbr="first">First Name</th>
  <th abbr="last">Last Name</th>
  <th abbr="age">Years of Age</th>
</tr>
</thead>
<tbody>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
</tbody>
<tfoot>
<tr>
  <td colspan="3">Summary: xxxxxxx</td>
</tr>
</tfoot>
</table>

<tfoot> Example Rendering

First Name Last Name Years of Age
xxxxxx xxxxxx xx
xxxxxx xxxxxx xx
Summary: xxxxxxx

Associating Data Cells with Headers

headers and id attributes

  • This pair of attributes explicitly tell the user agent (e.g., screen reader, browser) exactly which data cells go with which headers.
  • The id is the unique identifier that goes inside the header cell (the <th>).
  • The headers attribute typically goes inside the data cells (the <td>). Its value is the same value specified for the id.
  • The headers attribute can also be specified in <tr>.
  • As the table is linearized, the header is read aloud, then the data, then the next header, the next data, etc.
  • Multiple headers values can be included (all inside the same attribute value), as long as they are each separated by at least one space.
  • No visual impact on rendering.

headers and id Attributes Example

<table border="1">
<thead>
<tr>
  <th abbr="first" id="fname">First Name</th>
  <th abbr="last" id="lname">Last Name</th>
  <th abbr="age" id="age">Years of Age</th>
</tr>
</thead>
<tbody>
<tr>
  <td headers="fname">xxxxxx</td>
  <td headers="lname">xxxxxx</td>
  <td headers="age">xx</td>
</tr>
<tr>
  <td headers="fname">xxxxxx</td>
  <td headers="lname">xxxxxx</td>
  <td headers="age">xx</td>
</tr>
</tbody>
<tfoot>
<tr>
  <td colspan="3">Summary: xxxxxxx</td>
</tr>
</tfoot>
</table>

scope attribute

  • An alternative to the headers and id attributes is the scope attribute.
  • This can be applied to <th> and <td>.
  • Values of col, row, colgroup, and rowgroup are accepted.
  • Typically this is applied to <th>, specifying that the header applies to the column of data cells below (or the cells to the right, if the <th> is the first cell in a row within a tbody).
  • This approach requires less code than the headers / id approach.
  • We sacrifice the ability to represent complex data relationships, however, and tables are effectively limited to headers across the top or down the left (or right) sides.
  • No visual impact on rendering.

scope Attribute Example

<table border="1">
<thead>
<tr>
  <th abbr="first" scope="col">First Name</th>
  <th abbr="last" scope="col">Last Name</th>
  <th abbr="age" scope="col">Years of Age</th>
</tr>
</thead>
<tbody>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
</tbody>
<tfoot>
<tr>
  <td colspan="3">Summary: xxxxxxx</td>
</tr>
</tfoot>
</table>

Adding a Caption

<caption>

  • This tag provides a brief overview of the purpose and content of the table.
  • Its content is rendered in the browser.
  • This tag should be located immediately after the <table> tag.
  • The width of the caption is determined by the table width and its default location is above the table and centered.

<caption> Example

<table border="1">
<caption>Patient Demographics</caption>
<thead>
<tr>
  <th abbr="first" scope="col">First Name</th>
  <th abbr="last" scope="col">Last Name</th>
  <th abbr="age" scope="col">Years of Age</th>
</tr>
</thead>
<tbody>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
<tr>
  <td>xxxxxx</td>
  <td>xxxxxx</td>
  <td>xx</td>
</tr>
</tbody>
<tfoot>
<tr>
  <td colspan="3">Summary: xxxxxxx</td>
</tr>
</tfoot>
</table>

<caption> Example Rendering

Patient Demographics
First Name Last Name Years of Age
xxxxxx xxxxxx xx
xxxxxx xxxxxx xx
Summary: xxxxxxx