Ways to Make a UI Accessible—Part I

This follows on from my Let’s Try Harder With Web Accessibility article and will focus on practical tips you can apply in an effort to make your UI more accessible.

TIP 1: Apply Semantic HTML

Applying the most semantic HTML is the most effective and the easiest way to make a UI accessible. It is fundamental and often understated.

A UI’s structure is represented as an Accessibility Tree which is generated from the HTML DOM, plus information derived from CSS. Each node in the tree represents an element in the UI. Platform accessibility APIs use the Accessibility Tree and make it available to assistive technologies such as screen readers.

When you don’t take care to use the correct semantics in your HTML, assistive technologies will try and fill the gaps using certain strategies to try to cobble together information about the UI. These strategies should never be relied on.

Being syntactically correct in HTML does not make it semantically correct.

Someone speaking to you in broken English is difficult to understand, someone listening to a screen reader reading broken HTML is also difficult to understand, sometimes impossible.

The div element has no special meaning at all.
Authors are strongly encouraged to view the div element as an element of last resort, for when no other element is suitable. Use of more appropriate elements instead of the div element leads to better accessibility for readers and easier maintainability for authors.

There are two non semantic elements in HTML: `<div>` and `<span>`—HTML 4.0 deprecated presentational markup many years ago—before applying them think if they can be replaced with a semantic element. HTML5 has many to choose from, to name a few:

HTML5 semantic elements: Embedded content: `<video>`, `<audio>`, `<picture>`. Flow content: `<footer>`, `<header>`, `<main>`. Interactive content: `<details>`, `<summary>`. Metadata content: `<template>`. Phrasing content: `<datalist>`, `<mark>`, `<progress>`, `<time>`. Sectioning content: `<article>`, `<aside>`, `<nav>`, `<section>`.

Semantics also apply to attributes and attribute values. Apply attributes like the `<lang>` attribute so assistive technologies such as screen readers can use the correct language.

There are so many examples one could give for applying correct semantics to HTML but I’d like to cover one example of where incorrect semantics are often applied, which is using the `<a>` element for buttons that aren’t links.

Links go places, buttons perform actions.

If a link isn’t sending a user to a new document or to another area of the same document via a URI or fragment identifier in the `href` attribute then you probably need a `<button>` element.

Here’s an example of where Google incorrectly use a link for the button that reveals their users notifications:

HTML code for the button that reveals Google’s notifications.
Screenshot of Google’s notification drop down menu.

The `<a>` element Google have used isn’t sending the user to another document which is why there’s no `href` attribute present. Needing to leave off the `href` attribute should be a clear indicator that the `<a>` element would be better replaced with a `<button>` element.

You can see in this W3C document: HTML Accessibility API Mapping 1.0 that a link without a `href` attribute loses it semantic meaning, or in other words, its default WAI-ARIA role semantics is lost.

Screenshot from the HTML Accessibility API Mapping 1.0 W3C document showing the HTML Element Role Mappings for an `<a>` element without a `href` attribute, see: https://www.w3.org/TR/html-aam-1.0/#details-id-2.

Simply replacing the `<a>` element with a `<button>` element in this example will provide assistive technology users with a more accurate representation of this part of Google’s UI.

HTML code that uses a `<button>` element instead of an `<a>` element for the button that reveals Google’s notifications.

It’s rare but there are times when you don’t want to be semantic and applying the semantically meaningless `<div>` and `<span>` elements is the right thing to do.

Any purely presentational treatments in your UI that don’t require a text representation, for example, an upwards arrow used in a drop down menu, could make use of an empty `<div>` or `<span>` element. Though in this example using the CSS `::before` or `::after` pseudo elements would be a better choice. Any generic containers you need where it doesn’t make sense to use a semantic element, such as `<article>`, `<section>`, `<aside>`, etc., can be good candidates for the `<div>` element. Another example could be using a visually hidden `<span>` element within an already semantic element which contains text explaining the purpose of a purely visual part of a UI, a technique covered in TIP 3: Provide Context or Extra Context.

If you’re unsure about a HTML element’s purpose take a look at the W3C HTML5 specification to understand its meaning, and take some time to learn things like: Kinds of HTML content and HTML element role mappings, in addition to using resources such as HTML5 Accessibility.

TIP 2: Use the W3C Documentation

When building accessible UI’s it’s good to make use of the W3C documentation.

Screenshot of the authors W3C documentation Chrome browser bookmarks.

Bookmark documents like:

Even though this documentation can be a tad dry and dense it is the source of truth for when you’re wanting to understand things like:

  • The semantic meaning of HTML elements.
  • Definitions of WAI-ARIA roles, states and properties.
  • WCAG 2.0 Guidelines.
  • How to make a certain UI pattern accessible such as; an accordion, a dialog, etc. Some will no doubt argue against this 🙂.

Granted, you’re not going to find everything you need in the W3C documentation, there is always a lot of value in learning how other people in the industry are doing things. What’s important though, is to make sure to use an established design pattern as there is a ton of incorrect information out there, this is covered in more detail in Tip 4: Always Use Established Design Patterns.

TIP 3: Provide Context or Extra Context

It’s really common in UI’s to include purely visual treatments such as standalone icons—icons with no accompanying text. The UI you’re on right now (Medium) uses this treatment in their site header:

Screenshot of purely visual treatments in Medium’s header.

A sighted user may not necessarily need any text to accompany an icon like a magnifying glass to understand that it represents a search function as this is a ubiquitous pattern found on the Web.

But for users with visual impairments unable to see the magnifying glass icon how are they supposed to know what this part of the UI represents? This is what is meant by “Provide Context or Extra Context” and it’s the same concept as using the`alt` attribute with non-presentational images.

Out in the physical world we can see examples of this, here in Sydney, Australia, for example, pedestrian crossings play a sound to alert anyone who cannot see the “green man” signal that it is safe to cross the street.

A YouTube video of a Sydney, Australia pedestrian crossing that alerts pedestrians that it is now safe to cross the street.

Another example is braille being used on physical signs, such as this street sign found in Sydney, Australia:

Photograph of a street sign in Sydney, Australia, that uses braille and text for the street name.

We need to take the same care when building UI’s.

Whenever you don’t include a text node in a HTML element, such as a `<button>` element, you should stop and think and put yourself in the shoes of a visually impaired user who has to listen to the page. The best way to do this is to use a screen reader to test out the HTML you’re working on.

The Navigation set of Google Material Icons.

As seen in the Medium header and in the above image of the navigation set of Google Material icons, buttons that consist of just an icon are common examples of when text nodes are often absent, some additional examples of such buttons include:

  • Hamburger menu button, mostly found at small viewports in responsive UI’s.
  • Previous and next buttons, mostly found in UI patterns like carousels and pagination.
  • Close buttons, mostly found in UI patterns like dialogs and notifications.
  • Favourite/Star buttons, mostly found in social media UI’s.

Forms are also good examples of where not enough context is provided. Here are some common issues found in such forms:

  • Not using `<label>` elements to associate text labels with an input.
  • Not using `<legend>` elements to provide captions for a group of related form fields.
  • Not indicating which form fields are required.
Screenshot of Facebook’s global search form.
Screenshot of Twitter’s global search form.
Screenshot of Amazon.com’s global search form.

The examples above of compact single input forms such as the widely used global site search form, are often only built with sighted users in mind.

When viewing the HTML source of these forms you’ll often find that developers have neglected to provide a visually hidden `<label>` element to associate a text label with the text input, or neglected to include a text representation of the icon used in the form submit button. This sort of negligence can be costly and can really hinder the overall accessibility of your UI.

The following case studies from high traffic websites demonstrate where not enough context has been provided and for good measure an example of where its been done well 🙂.


One of Amazon.com’s UI patterns used throughout their website is a carousel, which you can see on their homepage, and pictured here:

Screenshot of one of Amazon.com’s UI carousels featured on their homepage.
HTML code for Amazon.com’s UI carousel previous and next buttons.

As well as the carousel’s previous and next buttons not having a text node, there are other issues:

  • Not semantically correct—see the hash being used in the `href` attribute? A `<button>` element is the correct element to use here.
  • The WAI-ARIA attribute: `aria-hidden=”true”` is applied to the `<a>` element resulting in assistive technologies completely ignoring the element as if it wasn’t there at all.

When encountering the previous and next button’s with a screen reader it’s not clear as to the purpose of each button. We can easily fix this (in addition to the other aforementioned issues) by applying visually hidden text within the semantically correct `<button>` element, like so:

HTML code for an improved version of Amazon.com’s UI carousel previous and next buttons.

The number preceding the word ‘items’ would be dynamic reflecting how many previous or next items are left in the carousel based on where you are in the carousel.

Another thing to point out is the use of the CSS helper class: `h-hide-visually` (the “h” at the start stands for “helper”) which hides a HTML element from sighted users but not from assistive technology users. Having a CSS helper class like this in your CSS architecture makes it really easy to provide more context to assistive technology users, the following are the recommended styles:

A CSS helper class to visually hide text.


Time’s website uses the ubiquitous pattern of the hamburger menu icon to reveal their website’s navigation:

Screenshot of the Time website header when viewed on a mobile phone device.

Unfortunately there isn’t a text representation associated with the icon, and like Amazon.com, Time are incorrectly using the `<a>` element:

HTML code for the Time website navigation menu button (hamburger icon).

It’s not entirely true that there’s no text representation for this button as a`title` attribute is present, however, the`title` attribute has dire support, if any, in assistive technologies.

To prevent assistive technology users having to guess the purpose of this button or even worse not realising it’s there at all we can apply a visually hidden text node in addition to switching out the `<a>` element for a `<button>` element, like so:

HTML code for an improved version of Time website navigation menu button (hamburger icon).

Also it’s worth noting that the text used within the `title` attribute isn’t optimal. It’s good practice to avoid words such as “click” as this word only represents one of the many pointer devices: a mouse, we have other pointer devices such as: keys on a keyboard, digits on a human hand, etc. The word “click” also unnecessarily focuses on the mechanics of actioning the mouse pointer device.

The Amazon.com and Time examples featured above could provide context in an alternative way: the WAI-ARIA attribute: `aria-label`. Using this attribute is the better way to handle providing more context to assistive technology users as that’s the entire purpose of the attribute, it also makes for less code as it doesn’t require any CSS that the text node implementation needs. If we were to apply the `aria-label` attribute technique to the Time hamburger menu button it would look like this:

HTML code for the Time website navigation menu button (hamburger icon) that uses the `aria-label` attribute instead of a visually hidden text node.

I personally choose to use a visually hidden text node hidden by CSS due to its far reaching support, not all assistive technologies fully support WAI-ARIA even though support for the `aria-label` attribute is pretty solid. What is important however, is to never use both at the same time, such as:

HTML code for the Time website navigation menu button (hamburger icon) that uses the `aria-label` attribute and a visually hidden text node.


As mentioned above forms often fall short in providing adequate context for assistive technology users, with the compact single input variety suffering the worst. And this is the case for Wikipedia’s global site search form:

Screenshot of Wikipedia’s in-page navigation and global search form.

The problem with this implementation is that the text input does not have a `<label>` element associated with it, as we can see here looking at the HTML:

HTML code for Wikipedia’s global site search form.

As already mentioned in the Time example using the `title` attribute is not an accessible solution and the same goes for using the `placeholder` attribute as a substitute for a `<label>` element, as noted in the HTML5.1 specification:

The placeholder attribute should not be used as a replacement for a label.—https://www.w3.org/TR/html51/sec-forms.html#the-placeholder-attribute

Making some simple updates to Wikipedia’s global site search form, as demonstrated below, will go a long way in making this important part of Wikipedia’s UI more accessible.

HTML code for an improved version of Wikipedia’s global site search form.

As well as adding a visually hidden `<label>` element, the following updates were also applied:


Twitter do a good job at providing sufficient context to various parts of their UI including their standalone icon buttons and compact single input forms, as we can see in the following examples.

First up is Twitter’s close button used in their “Compose new Tweet” dialog:

Screenshot of Twitter’s Compose new Tweet dialog.
HTML code for Twitter’s Compose new Tweet dialog close button.

Twitter have provided the visually hidden text node: “Close”, used a semantically correct HTML element: `<button>`, and provided WAI-ARIA attributes: `aria-controls` and `aria-describedby` to connect the button to it’s surrounding context, the dialog itself. Good job 👍.

Second up is Twitter’s global site search form:

Screenshot of Twitter’s global site search form.
HTML code for Twitter’s global site search form.

Twitter have provided a visually hidden `<label>` element that uses the text label: “Search query” to associate it with the text input, the submit button makes use of a visually hidden text node: “Search Twitter”, and the entire search form is wrapped in a `<div>` element that makes use of the WAI-ARIA “search” landmark role. Good job 👍.

To further improve this already semantically rich search form, the text input could make use of the “search” value of the “type” attribute.

In addition to the Amazon.com, Time, Wikipedia, and Twitter examples, there are plenty of other examples of where UI patterns can benefit from having more context, here are a few:

Menu Button

Screenshot of a Menu Button design pattern.

The Menu Button design pattern as defined in the WAI-ARIA 1.0 Authoring Practices document is a popular UI pattern especially found in Web applications. This pattern comes with very specific keyboard behaviour that may not be obvious to everyone, including non-assistive technology users.

It can be beneficial to advise users on how to operate this design pattern using their keyboard which we can do by applying some visually hidden text, such as:

Open the sub menu with the enter key and close it with the escape key; use the up and down arrow keys to navigate.

The HTML code:

HTML code of an accessible Menu Button.

There are established patterns we can use to surface this information for sighted users, such as a tooltip indicated by a “help” themed icon.

Navigation blocks

Navigation blocks are crucial parts of a UI with some benefiting from having additional context, context applied by the WAI-ARIA `aria-label` attribute, and this is in addition to the extra context provided by the HTML5 `<nav>` element and if you need far reaching support: the WAI-ARIA “navigation” landmark role.

This technique is explained and demonstrated really well in the Adding context using containers section of the UX accessibility with aria-label article, and here is the HTML taken verbatim from one of the navigation blocks featured in this article:

HTML code for a navigation block that includes extra context provided by the `aria-label` attribute in addition to the `nav` element and ARIA landmark role of `navigation`.

Empty states

Some UI components can have an empty state applied to them. This state typically shows users that no data yet exists for the component with parts of these states being represented in a purely visual way.

Screenshot of a fictional Report Metric component empty state.

The above example of a fictional Report Metric component shows the component’s empty state on the right. The design features an em dash instead of a zero in the four sub set of metrics. A sighted user can make the connection that no metric data is yet available, but for non-sighted users they’ll most likely be left wondering why only the metric label is read out then followed by (however their assistive technology announces it) the em dash. The VoiceOver screen reader reads it out like this:

Avg open rate
em dash
Avg click rate
em dash
Avg unsubscribed rate
em dash
Avg bound rate
em dash

We could improve this experience by providing some visually hidden text which consists of either a zero or something more detailed such as “None so far”. The VoiceOver screen reader reads this out like this:

Avg open rate
None so far
Avg click rate
None so far
Avg unsubscribed rate
None so far
Avg bound rate
None so far

Because we still need to keep the em dash for sighted users we can make use of the WAI-ARIA attribute: `aria-hidden` and apply the visually hidden text node the standard way, like this:

HTML code for demonstrating how to accessibly hide an em dash and add a visually hidden text node to a Report Metric component.

Tip 4: Always Use Established Design Patterns

I don’t think it’s all that uncommon that Web Developers and Web Designers question established UI design patterns, I know I’ve experienced this with people I’ve worked with in my career and I’ve been guilty of doing it myself.

Personally, I’ve found this comes from a place of innocent ignorance, but implementing the wrong accessible solution, especially when it involves WAI-ARIA, can actually be worse than doing nothing at all.

So we should always do our best to implement established design patterns when it comes to accessibility and strongly avoid implementing solutions that we think is right. This Medium article titled: Danger! Testing Accessibility with real people written by Léonie Watson covers this really well.

One common example I’ve experienced a few times in my career is the questioning of the keyboard behaviour of a tabbed interface, such as:

Screenshot of a tabbed interface from the Salesforce Lightning Design System, see: https://www.lightningdesignsystem.com/components/tabs/.

I think it’s questioned because some people feel the keyboard behaviour doesn’t feel intuitive enough, for example, some feel that the next tab stop after the first tab (ITEM ONE in the above example) should be the next tab (ITEM TWO in the above example) not the correct behaviour of the next tab stop being the first natively focusable element within the tab panel or if one doesn’t exist then the first natively focusable that comes directly outside of the tab panel.

There are many examples out there for accessible solutions and knowing which ones to implement is key but also hard. One of the best resources I’ve used is the Design Patterns section of the WAI-ARIA 1.0 Authoring Practices document created by the W3C. It features some of the most popular UI design patterns including a tabbed interface, or the Tab Panel (widget) as its called in the document, letting you know each pattern’s keyboard functionality and WAI-ARIA roles, states, and properties. The one thing lacking however are some of the examples. Some other good resources:

Stick to established patterns and get in the habit of testing your UI with a screen reader (this will be covered in more detail in Part II of the article) and your UI’s will be more accessible for it.

And that concludes Part I of this article. I hope this has provided some useful tips in making UI’s more accessible, and contributed to making the Web a more accessible place. Stay tuned for Part II.