5 ways to improve table accessibility

I recently came across this example of an HTML table that was marked up correctly, for the most part, but lacked some of the important coding nuances needed to make a table truly accessible. Below is a screen shot of that table with the areas of concern highlighted.

screenshot of an HTML table with 4 columns, a header row, and 6 data rows. Areas of the table are highlighted with the numbers 1 through 5.

Depending on the complexity of your table, it can be helpful to review the Table Concepts tutorial from the W3C Web Accessibility Initiative (WAI).

Here are five things to check when creating your next table.

1) Caption that table

While this table has what looks like a caption of “Choose a plan”, that text was actually marked up as a heading level <h3>. Moving it inside the <table> element and marking it up as a <caption> instead allows assistive technologies (AT), like a screen reader, to announce the text as being programmatically associated with the <table>.

Table with 7 rows and 4 columns, caption, choose a plan

NVDA screen reader

2) Include header text for every column

In this example, the very first table cell is empty. The screen reader announces: row 1 column 1. That’s it. But what about the contents of the rest of the cells in this column? They need a header to explain what they are. Visually, the content author doesn’t want a header for column one, but AT users benefit when the name of the column is announced before the contents of subsequent cells.

To fix this issue, I added a hidden column header for column one of “plan feature.”

<th><span class="visually-hidden">Plan feature</span></th>

Now, when a screen reader gets to the beginning of a new row, it’s clear what content is contained in the first cell of each row.

Row 3, plan feature, column 1, number of users

NVDA screen reader

3) Use alt attributes meaningfully

The content author decided to use green check mark images to indicate when a plan feature is included in a particular plan, but they didn’t include alt attributes. AT users have no way of knowing when a feature is included because the cells with images don’t communicate anything.

To fix this, make sure you include alt text on images that provides meaning to the user. An alt attribute of “check mark” would not be meaningful even though it’s visually correct. Instead, I used “feature included.” (Though I would argue using an icon font would be better than an image.)

<td><img src="icon-checkmark-green.svg" alt="feature included"></td>

Team plan, column 3, [graphic] feature included

NVDA screen reader

4) Have data in every table cell

When a feature is not included, we must also communicate that to AT users. The last row of the table has three empty cells which indicate to sighted users that a feature is not included, but like 2) above, we need to add some hidden helper text.

<td><span class="visually-hidden">not included</span></td>

Personal plan, column 2, not included

NVDA screen reader

5) Check your (con)text

Screen readers don’t always handle abbreviations and punctuation as expected. I found two interesting examples with this table. First, the number of users for the Team plan visually looks like “2-50” but it gets announced as “250” because the hyphen is ignored. To accurately convey this meaning, we can add the word “to” as visually-hidden helper text, and we can hide the hyphen from AT to be safe.

<td>2<span aria-hidden="true">-</span><span class="visually-hidden">to</span>50</td>

Team plan, column 3, two to fifty

NVDA screen reader

Second, the plan feature “2FA” in row six does not get announced properly. My screen reader announces this as “2-fah”, not “2-F-A”. Again we need to add helper text for AT users.

<td><span aria-hidden="true">2FA</span><span class="visually-hidden">2 factor authentication</span></th>

Row 6, plan feature, column 1, 2 factor authentication

NVDA screen reader

Please check out the full HTML for this <table> in my first Codepen entry.

See the Pen Accessible Table by Rachele (@racheleditullio) on CodePen.

Creating useful alternative text for your images

Providing alternative text (alt text) for images is necessary to pass success criterion 1.1.1: Non-text content. On many of the websites I evaluate, it’s very common for alt text to be incomplete, incorrectly applied or missing entirely. When performing accessibility testing, I find it helpful to use a tool like this image bookmarklet to highlight all the images on the page and display their alt attributes.

screen shot of two images with alt attributes displayed by a bookmarklet tool.
Two webpage images highlighted using a bookmarklet tool for alt attributes

The key to writing good alt text is to consider the purpose of the image when trying to decide how to describe its meaning. Let’s look at five types of webpage images:

  1. Informative
  2. Actionable
  3. Decorative
  4. Redundant
  5. Complex

Informative images

These are images intended to convey pertinent information to the user. Most images in the main content of a webpage, like a photo supporting a news story, are informative images.

  • Informative images must have programmatically-discernible alt text that is accessible to people using assistive technologies (AT) like screen readers and braille displays.
  • Alt text must be meaningful and accurately convey the purpose and intent for those who can’t see it.
  • Alt text shouldn’t include words that identify the element as a graphic or image because screen readers announce that automatically.
  • Alt text should be concise. (We will look at complex images that require long descriptions separately.)

Let’s look at an example. Below is a screen shot of a table with two columns. Each table row lists a feature in the first column and has an icon of a check mark in the second column. The content author gave the check mark icon alt text of “check mark”.

screenshot of the header row and 2nd row of a table. the first column is labeled what's included and the 2nd column has a checkmark icon.
Alt text provided: check mark
<img class="block--center" src="icon-check.svg" alt="check mark.">

But what is the actual meaning of the symbol of a check mark in this context? It’s there to indicate visually which features are included. Better alt text would be the word “yes” because that conveys through text what the icon conveys symbolically. A screen reader would announce:

Row two column one What’s included
Product research and development
Row two column two Included

Tip: End your alt text with a period (full stop). This prevents it from being announced by a screen reader like a run-on sentence with text that follows.

Actionable images

Any time an image is used as a link, button or control, it must provide alt text that conveys its purpose in that context so that AT users understand what will happen if they follow the link or activate the control. Let’s look at the following carousel banner image:

screenshot of an image with lots of embedded text.
Alt text provided: Forrester names OpenText a leader in ECM Content Platforms. Read the report.
<a href="/info/forrester-wave">
<img src="forrester-wave.jpg" alt="Forrester names OpenText a leader in ECM Content Platforms. Read the report.">

When an image is used as a link, its alt text must explain the purpose of the link or control.

Tip: Avoid embedding text in images when it’s possible to display the content using real text.

Decorative images

When an image serves a purely visual function, it doesn’t need to convey anything to AT users. All inline images must include the alt attribute on the <img> element but it can be empty when the context is decorative. If the alt attribute is missing, though, a screen reader will often try to announce the file name instead of moving past it to the next block of text.

screen shot of a block of text and link with a decorative image above it.
Decorative image, no alt attribute value needed
<img src="circuit-board.jpg" alt="">

Redundant images

Sometimes, an image is redundant because its context is conveyed by adjacent text. Like decorative images, it’s okay to have a null value for the image’s alt attribute if it doesn’t need to convey additional meaning to AT users. In the image below, a circle icon with the word “Process” is visible to the left of a heading reading “Digital Process Automation.”

screen shot of an icon with text that is redundant to the adjacent heading.
<img src="icon-process.svg" alt="">
<h2>Digital Process Automation</h2>

The icon is redundant to the heading text and serves a mostly decorative purpose. It doesn’t convey additional meaning.

Complex images

When an image is complex in nature, like a chart or diagram, alt text should should describe the image briefly. Provide a complete explanation in an associated long description. Some content authors use a supporting element like <figcaption> with an aria-describedby attribute to programmatically link the <figcaption> to <img>.

screen shot of a complex diagram with three circles and lots of embedded text.
Alt text provided: Diagram of the OpenText intelligent and connected enterprise.
<img aria-describedby="long-desc" alt="diagram of the OpenText intellgent and connected enterprise." src="opentext-intelligent-and-connected-enterprise-graphic.jpg">
<figcaption id="long-desc">The OpenText EIM Suite and OpenText Cloud combine to support EIM applications and EIM platforms with an intelligent information core of automation, AI, APIs and data management.</figcaption>

The long description should be visible for sighted users as well as they might benefit from the robust explanation, particularly when it comes to lengthy charts and graphs.


Alt text is both simple and complicated at the same time but a little forethought into the purpose of your images in each context goes a long way towards making them meaningful for AT users who won’t perceive them visually.

Accessibility review of the We Are Blood online questionnaire

I’m a regular blood donor with our local blood bank, We Are Blood. If you’ve ever donated blood, you know that part of the process is answering a bunch of health-related questions first to help determine your eligibility. Being sick, taking certain medications or having had certain illnesses can exclude you from donating.

I’m donating blood this Friday and was thrilled when today’s reminder email announced a new option to complete the pre-donation questionnaire online, before coming in for my appointment. I decided to check this process for web accessibility. Let’s begin!

Welcome to QuickPass page

The email links to the Welcome to QuickPass! page which has a lot of accessibility issues, and this is just the instructions. I ran both the Lighthouse and Axe accessibility audits in Chrome and the results were not good.

  • Lighthouse score: 47/100
  • Axe automated issues found: 28
Screenshot of the top of the Welcome to QuickPass page

Some site-wide issues

  • The entire We Are Blood website is missing a “skip to content” link that would allow users to bypass the repetitive navigation links.
  • The “We Are Blood” logo is embedded SVG code that does not provide any text alternative and is announced by the NVDA screen reader as “weareblood.org link.” The logo should include a <title> element with the text “We Are Blood. Drawn together since 1951.” Doing this will enable a screen reader to communicate the logo to users with visual impairments who cannot see it.
  • The five links in the site’s main navigation all have dropdown menus that are accessible on mouse hover only. To be accessible, users must be able to use all website components with a keyboard.
screenshot of the dropdown menus on the We Are Blood website.
  • The newsletter signup form in the footer uses positive tabindex values. The result? When a keyboard user tabs from the browser address bar into the page, the first focusable element is the “Full Name” field in the form, which is confusing because it violates the natural reading order of the content. The second focusable element is the “Email Address” field. The third focusable element, though, is not the form submit button—it’s the “We Are Blood” logo link because after the positive tabindex values, the tabindex goes to the beginning of the content.
  • The newsletter signup form submit button is missing a text label. The screen reader announces “Contentinfo landmark button.”
  • The newsletter signup form fields use placeholder text instead of <label> elements.
screenshot of the newsletter signup form showing the two fields have positive tabindex values.

There are several color contrast issues where the contrast ratio between the text color and background color fails to meet the 4.5:1 requirement for regular, unbold text. For example, the gray text in the screenshot below from the footer has a contrast ratio of just 3.13 on a light blue background.

screenshot showing poor color contrast of gray text on a light blue background.

Content issues

Arguably, the most important thing on this page is the link to start the questionnaire. While visually it looks like there is a big button that reads “Click here for QuickPass,” a screen reader announces “welcome cust=WRB link” because no alternative text is provided on the image. The alt attribute must contain the same text that is in the image.

click here for QuickPass button.
<img class="aligncenter wp-image-2040 size-full" src="http://weareblood.org/wp-content/uploads/2018/05/QuickPass-Click.jpg" alt="" srcset="https://weareblood.org/wp-content/uploads/2018/05/QuickPass-Click.jpg 600w, https://weareblood.org/wp-content/uploads/2018/05/QuickPass-Click-150x57.jpg 150w, https://weareblood.org/wp-content/uploads/2018/05/QuickPass-Click-300x113.jpg 300w" sizes="(max-width: 600px) 85vw, 600px" width="600" height="226">

The page content skips heading levels. It starts correctly with <h1> for the “Welcome to QuickPass!” main heading, but then skips to <h4> for the heading “A couple of key points”, then to <h3> for headings in the footer.

QuickPass questionnaire pages

The questionnaire begins on the ABO QuickPass page.

  • Lighthouse score: 43/100
  • Axe automated issues found: 6

This start page does not support keyboard or screen reader usage because the entire thing is marked up as a form. Screen readers enter a different mode when they encounter a form, which disables the navigation hot keys, in order to allow users to type in form fields.

screenshot of the questionnaire start page with overview text and a large button that reads start questionnaire.

Here is how the body copy is marked up inside the <form> element:

<h1 style="text-align:center">
<font color="#E36B50">Hey Blood Donor!</font><br><br>
<font color="#01426a">Thank you in advance for taking the time to fill out this questionnaire.<br><br>Please ensure you are answering all questions in a private, confidential setting and that you read each question in its entirety before answering. Skip the question if you do not understand or have questions of your own.<br><br>Please note that your questionnaire answers are good for today only and that additional questions will need to be answered at the donation site.</font></h1>

Donor information page

Since this page actually contains form fields, it works better with the keyboard and screen reader, but it still has serious HTML markup issues.

  • Lighthouse score: 55/100
  • Axe automated issues found: 5
screenshot of the donor information request form with fields for name, gender and birth date.

Here’s the markup for the “First Name” field:

<span class="formleadinglabel">First Name:<span class="required-indicator desktop">*</span></span>
<span class="formfield">
<input type="text" id="firstname" name="firstname" maxlength="15" class="required" value="" autofocus="" autocomplete="given-name" placeholder="First Name">
<span class="required-indicator in-field mobile">*</span></span>
  • The form field labels are not <label> elements and, therefore, are not associated programatically with their <input> elements.
  • None of the text input fields are announced as required.
  • The day, month and year combo boxes are not announced as being for “Birth date” so screen reader users have no idea what date they’re being asked to enter.

Even if keyboard users are able to complete the form fields, they cannot continue to the next screen because the “Continue” control isn’t marked up as a button, preventing it from gaining keyboard focus. It’s also a background image without any text alternative.

<div id="btnContinue"></div>

Question pages

I didn’t complete the entire questionnaire today but the question screen has repeatable patterns and problems.

screenshot of the individual questions within the QuickPass app which have a question and three radio buttons for yes, no or skip.
  • The volume controls do not have text labels, which is really ironic if you think about someone trying to use this with a screen reader.
  • Keyboard users cannot tab to the radio buttons or select an answer.
  • There are two <label> elements per radio button <input> and the one with a text label has a CSS class which hides it. 🤦 The screen reader announced “clickable, clickable, clickable.” Here’s the markup:
<input id="yes" class="answers" type="radio" name="answer" value="Y">
<label class="default-label" for="yes"></label>
<label for="yes" class="hidden">yes</label>

I am happy to have the option to complete these questions before I head to the blood bank, but it’s not accessible for many people with disabilities. I hope We Are Blood requests that the vendor make its software comply with the Web Content Accessibility Guidelines so that everyone can use it.