Tables in HTML serve two main purposes: web page layout and organizing data. For the record, it is strongly recommended that you DO NOT use tables for layout purposes on your website.
From an accessibility standpoint, screen reading users must navigate using a different set of keyboard keystroke combinations than they would outside of a table. This could create unique accessibility and usability issues for individuals who are blind or low vision.
Relevant WCAG Guideline(s): WCAG 1.3.1 (Info and Relationships) opens a new window
For information on how to create accessible tables, see below:
- Basic structure of an HTML table
- Using column and row headers to improve accessibility
- Making complex tables more accessible
- Table caption & summary elements
- Additional resources
Basic Structure of an HTML table
Below is an example of a simple HTML table (i.e., sample course schedule for two GMU students):
Monday | Tuesday | Wednesday | Thursday | Friday | |
Eric | FREN 100, 9:00am-10:15am | MATH 100,1:30pm-2:45pm | No class | MATH 100, 1:30pm-2:45pm | BIOL 100, 3:30pm-4:45pm |
Jessica | ENGL LAB 200, 9:00am-11:00am | No class | ENGL LAB 200, 9:00am-11:00am | No class | ENGL LAB 200, 9:00am-11:00am |
Classes (i.e., demotable, firstrow, and firstcol) have been added that allow me to style the background color of those header cells grey and change the text to white. Visually, it is easy to identify what the actual header cells are. Unfortunately, the underlying code identifies every table cell the same way using the td tag. See the code snippet below:
HTML code snippet:
<table class="demotable">
<tr class="firstrow">
<td></td>
<td>Monday</td>
<td>Tuesday</td>
<td>Wednesday</td>
<td>Thursday</td>
<td>Friday</td>
</tr>
<tr>
<td class="firstcol">Eric</td>
<td>FREN 100, 9:00am-10:15am</td>
<td>MATH 100,1:30pm-2:45pm</td>
<td>No class</td>
<td>MATH 100, 1:30pm-2:45pm</td>
<td>BIOL 100, 3:30pm-4:45pm</td>
</tr>
<tr>
<td class="firstcol">Jessica</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
</tr>
</table>
This is a problem because screen readers use the underlying th (i.e., header cells) and td (i.e., data cells) tags to distinguish between header cells and data cells. Without this differentiation, it is not possible for screen reader users to know how information within the table is intended to be read.
Let’s take a look at home the table above would be read by a screen reader:
Screen Reader Output…
Monday, Tuesday, Wednesday, Thursday, Friday, Eric, FREN 100, 9:00am-10:15am, MATH 100, 1:30pm-2:45pm, No class, MATH 100, 1:30pm-2:45pm, BIOL 100, 3:30pm-4:45pm, Jessica, ENGL LAB 200, 9:00am-11:00am, No class, ENGL LAB 200, 9:00am-11:00am, No class, ENGL LAB 200, 9:00am-11:00am
While the screen reader can access the data in each cell, it is difficult to make sense of it if you are only presented with data one cell at a time.
The table below is a more accurate visual representation of how table data (without table headers) is presented to a screen reader user at any given time:
MATH 100, 1:30pm-2:45pm | |||||
As you can see in this example, the screen reader announces the data in the highlighted cell but no context is provided to help the user understand the information (i.e., Eric’s Thursday class).
Using column and row headers to improve accessibility
Continuing with the sample table from the previous section, let’s add table headers (i.e., th tags) to properly identify both the column and row headers in the table (See the HTML code snippet below):
HTML code snippet:
<table class="demotable">
<tr class="firstrow">
<th></th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
</tr>
<tr>
<th class="firstcol">Eric</th>
<td>FREN 100, 9:00am-10:15am</td>
<td>MATH 100,1:30pm-2:45pm</td>
<td>No class</td>
<td>MATH 100, 1:30pm-2:45pm</td>
<td>BIOL 100, 3:30pm-4:45pm</td>
</tr>
<tr>
<th class="firstcol">Jessica</th>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
</tr>
</table>
Now, screen reader applications are able to properly associate the header cells with the data cells. See below for how a screen reader would interpret this information:
Screen Reader Output…
Monday, Tuesday, Wednesday, Thursday, Friday, Eric, MONDAY, FREN 100, 9:00am-10:15am, TUESDAY, MATH 100, 1:30pm-2:45pm, WEDNESDAY, No class, THURSDAY, MATH 100, 1:30pm-2:45pm, FRIDAY, BIOL 100, 3:30pm-4:45pm, Jessica, MONDAY, ENGL LAB 200, 9:00am-11:00am, TUESDAY, No class, WEDNESDAY ENGL LAB 200, 9:00am-11:00am, THURSDAY, No class, FRIDAY, ENGL LAB 200, 9:00am-11:00am
By simply adding the th tags, the header cells are now announced prior to the cell data being announced. This change provides more information to the screen reader user, thus allowing for a better understanding of the information being presented. Below is an updated visual representation of how the table data is presented to a screen reader user:
Thursday | |||||
Eric | MATH 100, 1:30pm-2:45pm | ||||
As you can see, in addition to the cell data that is in focus (highlighted in yellow), the screen reader user also has both the column header and row header data (if applicable) available to them. In this instance, as they first encounter the cell, it may read ERIC THURSDAY MATH 100, 1:30pm-2:45pm (depending on how they navigate the table). Either way, the end user has the necessary information to make sense of the cell data.
Making complex tables more accessible
Whenever possible, keep your tables simple. I will repeat that…whenever possible, keep your tables simple! In other words, use a single row for column headers, a single column for row headers, and never used merged or split cells. This limits confusion on the part of the end user and makes it much easier for you as the content author/developer to make your data accessible. Also, screen readers do not reliably support complex tables which can greatly impact user experience.
The scope attribute
The scope attribute defines whether a header cell spans a column or a row. Given that most screen readers require only the th
tag nowadays to appropriately, identify table headers, this may seem a bit redundant. However, this attribute provides valuable information for screen reader users when you have more complex table configurations.
Let’s take a look at how this is used in the example below:
HTML code snippet:
<table class="demotable">
<tr class="firstrow">
<th></th>
<th scope="col">Monday</th>
<th scope="col">Tuesday</th>
<th scope="col">Wednesday</th>
<th scope="col">Thursday</th>
<th scope="col">Friday</th>
</tr>
<tr>
<th class="firstcol" scope="row">Eric</th>
<td>FREN 100, 9:00am-10:15am</td>
<td>MATH 100,1:30pm-2:45pm</td>
<td>No class</td>
<td>MATH 100, 1:30pm-2:45pm</td>
<td>BIOL 100, 3:30pm-4:45pm</td>
</tr>
<tr>
<th class="firstcol" scope="row">Jessica</th>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
</tr>
</table>
Although the visual representation of the table remains unchanged, this additional information allows screen reader applications to properly associate the header cells with the data cells in complex table configurations.
The colspan and rowspan attributes
Let’s consider another example using a more complex table configuration. Continuing with our previous table, we will now include an additional column header. See below:
Fall Course Schedule | |||||
---|---|---|---|---|---|
Monday | Tuesday | Wednesday | Thursday | Friday | |
Eric | FREN 100, 9:00am-10:15am | MATH 100,1:30pm-2:45pm | No class | MATH 100, 1:30pm-2:45pm | BIOL 100, 3:30pm-4:45pm |
Jessica | ENGL LAB 200, 9:00am-11:00am | No class | ENGL LAB 200, 9:00am-11:00am | No class | ENGL LAB 200, 9:00am-11:00am |
The colspan and rowspan attributes specify the number of cells that a column or row should span. This is necessary when using complex tables with merged cells. By default, table cells only span 1 column and row. Let’s demonstrate how this works using the colspan
attribute (see Figure 1 below).
Adding the colspan="6"
attribute as a part of the th
tag defines this new table header cell as spanning across 6 columns (see Figure 2 below). This allows people viewing your table to more easily associate the new merged table header with the data in the table.
The HTML code snippet below now includes both the colspan
and scope
attributes:
HTML code snippet:
<table class="demotable">
<tr class="firstrow">
<th style="text-align: center; color: yellow; font-weight: bold;" colspan="6">Fall Course Schedule</th>
</tr>
<tr class="firstrow">
<th></th>
<th scope="col">Monday</th>
<th scope="col">Tuesday</th>
<th scope="col">Wednesday</th>
<th scope="col">Thursday</th>
<th scope="col">Friday</th>
</tr>
<tr>
<th class="firstcol" scope="row">Eric</th>
<td>FREN 100, 9:00am-10:15am</td>
<td>MATH 100,1:30pm-2:45pm</td>
<td>No class</td>
<td>MATH 100, 1:30pm-2:45pm</td>
<td>BIOL 100, 3:30pm-4:45pm</td>
</tr>
<tr>
<th class="firstcol" scope="row">Jessica</th>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
<td>No class</td>
<td>ENGL LAB 200, 9:00am-11:00am</td>
</tr>
</table>
This change provides additional information, allowing the screen reader user to associate the data in the table with both the new (Fall Course Schedule) and nested headers (i.e., Monday, Tuesday, etc.). Below is an example of how that information might be interpreted:
Screen Reader Output…
FALL COURSE SCHEDULE, Monday, Tuesday, Wednesday, Thursday, Friday, FALL COURSE SCHEDULE, Eric, FALL COURSE SCHEDULE, MONDAY, FREN 100, 9:00am-10:15am, FALL COURSE SCHEDULE, TUESDAY, MATH 100, 1:30pm-2:45pm, FALL COURSE SCHEDULE, WEDNESDAY, No class, FALL COURSE SCHEDULE, THURSDAY, MATH 100, 1:30pm-2:45pm, FALL COURSE SCHEDULE, FRIDAY, BIOL 100, 3:30pm-4:45pm, FALL COURSE SCHEDULE, Jessica, FALL COURSE SCHEDULE, MONDAY, ENGL LAB 200, 9:00am-11:00am, FALL COURSE SCHEDULE, TUESDAY, No class, FALL COURSE SCHEDULE, WEDNESDAY ENGL LAB 200, 9:00am-11:00am, FALL COURSE SCHEDULE, THURSDAY, No class, FALL COURSE SCHEDULE, FRIDAY, ENGL LAB 200, 9:00am-11:00am
I will reiterate, it is strongly suggested that you avoid the use of split or merged cells in your tables whenever possible. Support for these attributes will vary depending upon the type of screen reader used. With that said, using these attributes should assist with making your complex tables as accessible as possible.
Table caption and summary elements
Although table caption and summary elements are not required, they can provide valuable information to the end user. Consult the W3C’s Web Accessibility Tutorial on Table Caption & Summary opens a new window for additional information.
Additional Resources
- W3C Web Accessibility Tutorial: Table Concepts opens a new window
- WebAIM: Creating Accessible Tables opens a new window