Writing and designing for accessibility (videos)

I feel really privileged to have worked with Alastair Lee at Panda and Giles Turnbull at Use the Human Voice over the last few weeks to produce a series of short videos about content design and accessibility.

It’s been part of the Catalyst Definition Programme, mentoring UK charities as they turn their user research into ideas and solutions to problems. All the videos are freely available on YouTube, so why not take a look:

Writing and designing for accessibility – three short videos by Jon Gibbins with advice and tips for creating more accessible content.

Content design foundations – seven videos by Giles Turnbull introducing the aspects of content design thinking.

Making sustainability accessible

Last week, I spoke at a Future Economy Network event about the importance of accessibility as part of sustainable development. There are slides on SlideShare, but the essence of my talk is outlined below.

Leave No One Behind

This is one of the core principles of the United Nations 2030 Agenda for Sustainable Development. If something does not work for all people, it is prone to risk and not sustainable.

If we exclude people in our work, then we create products and services that are less sustainable. And as we look to the future, our idea of what it means to be inclusive and sustainable is likely to shift. We have a growing, ageing population. In fact, it’s estimated that by 2060 there will be twice as many older people than younger people. This relates to the ‘people’ pillar of the triple bottom line and the definition of sustainability:

Around 1 in 5 people have a disability – more than a billion people in the world. Looking after our planet is a team sport. We need to include disabled people. We need their help.

Sustainable goals

Accessibility is a measure of social sustainability. In fact, disability is explicitly mentioned 11 times in Agenda 2030, and relates directly to 5 of the UN’s 17 sustainable development goals (SDGs):

  • Goal 4, Quality education: Access to knowledge and awareness.
  • Goal 8, Decent work and economic growth: Access to employment.
  • Goal 10, Reduced inequalities: Social, economic and political inclusion for disabled people.
  • Goal 11, Sustainable cities and communities: Accessible human settlements.
  • Goal 17, Partnerships for the goals: Data and monitoring of the UN’s Sustainable Development Goals.

And accessibility impacts on yet more of the goals, for example, “Access to health services”.

Inclusion is encompassed by yet more parts of the goals and their targets and topics:

  • Gender equality
  • Financial inclusion

Through a COVID lens…

The COVID-19 pandemic has tested the resilience of many businesses, but also every one of us as individuals. We have a greater understanding of what it is to feel isolated or excluded. But for many disabled people, the pandemic has amplified the effects of social inequality around the world.

Disability inclusion isn’t a tick-box exercise. It’s vital to achieving the SDGs.

Android keyboard shortcuts cheat sheet

Did you know you can control your Android devices using a Bluetooth keyboard? I use a keyboard to test apps on Android for accessibility. Having to remember keyboard commands across multiple platforms, one can get quite confused. This is why I have a series of cheat sheets to help me when my memory fails me.

Earlier in the month I popped my rough and ready cheat sheet for Android keyboard commands up on Github for anybody to use or contribute to:

Android keyboard shortcuts

I’ll be adding more resources here over the coming weeks, so stay tuned.

11/11 – Don’t mention the war

460 Squadron RAAF crew

I’ve just spent the 2-minute silence contemplating my late father’s involvement in the Second World War, how proud I am of him, and what he thought of the Britain in which he passed away just two weeks ago.

Dad always told me that he “fought in World War II for Europe”. He fought for peace, he was pro-Europe, and had many European friends. Heck, even our family’s ancestors came to Britain from Germany centuries ago.

On this day, please don’t use the First or Second World War as justification for Brexit, or make the wars about patriotism and national pride. While we should be glad and thankful that the Allied forces united and won those wars, those who “fought for their country” really fought for freedom and democracy for all people, mustered by the rhetoric of patriotism and national pride. They fought against fascism, signs of which we are sadly seeing increase worldwide.

The wars were awful and millions of people died, so let’s not allow wartime to be humanity’s heyday.

WAI-ARIA: the dark art of accessibility?

When I’m auditing sites for accessibility issues, I find that WAI-ARIA has been used in an attempt to improve the accessibility of the content. And that’s exactly why WAI-ARIA exists, but so many implementations misunderstand how the tools provided by WAI-ARIA should work together.

A few weeks back I was interviewed on the A11y Rules podcast by Nic Steenhout. In it, I discuss what I believe to be the biggest barrier to a more accessible World Wide Web, which I believe to be awareness. In my experience, it’s not that there is a lack of willingness by web developers to incorporate accessibility, but rather that there is much confusion and misunderstanding of how accessibility technically works and what is expected of web developers. And at an organisational level, there is often a commitment to accessibility, but little culture of accessibility throughout various teams that each have a role to play in creating accessible digital products.

I end the interview with Nic by saying that accessibility is not a dark art. That said, one area of accessibility that often stumps even the most experienced developers, is WAI-ARIA – the Accessible Rich Internet Applications (ARIA) specification.

So, combining these two thoughts together, this is an awareness-raising blog post for web developers about ARIA. It was prompted by an issue discovered on a client’s website that was using a carousel powered by Slick. I’m going to take a look at some of the ARIA used by Slick.

In summary (tl;dr)

One of Slick’s demos includes the following code hierarchy:

<div role="toolbar">
  <ul role="tablist">
    <li role="presentation" aria-selected="true" aria-controls="[invalid id]">
      <button role="button" tabindex="0">

In summary, the issues are:

  1. ARIA toolbar and tablist roles are mixed together.
  2. The tablist contains no elements with tab roles.
  3. The aria-selected state and aria-controls attributes are applied to inappropriate elements.
  4. aria-controls attributes reference element IDs that do not exist in the page.
  5. The <button> element’s role is duplicated by role="button".
  6. The tabindex="0" applied to the <button> is unnecessary.

What is WAI-ARIA?

The Accessible Rich Internet Applications specification is maintained by the WAI at the W3C. It provides a toolkit of attributes that allow us to enhance the native roles of HTML elements to build more accessible user experiences.

These days, HTML alone does not provide enough of a toolkit to build a desktop-like experience on the Web, so we build custom controls using lots of JavaScript. This is great, but to do so in an accessible manner, we need some additional tools to fill in the gaps in HTML’s teeth.

What’s your beef with Slick, huh?

Before I get started, I don’t mean to pick on Slick here, but it struck me as a good example of where even expert JavaScript developers can build for accessibility and still get things wrong.

The accessibility community doesn’t much like carousels as they embody several accessibility and usability issues, even when the individual components that make up a carousel are made technically accessible. This has resulted in resources like shouldiuseacarousel.com being born, demonstrating some of the issues.

Slick’s demos have obviously been built with accessibility in mind, which is great. However, some basic misunderstandings have resulted in some poor ARIA implementations.

Examining the code

In the interests of time and clarity, I’m not going to take you through every issue with Slick’s demos, but rather look at one part of the interface: the navigation dots for the carousel in the “Single Item” demo.

The navigation dots for Slick’s demo carousels are implemented as a tab list. We can extract the following DOM hierarchy from the HTML used:

<div role="toolbar">
  <ul role="tablist">
    <li role="presentation" aria-selected="true" aria-controls="[invalid id]">
      <button role="button" tabindex="0">

What are the problems here? Let’s examine this code snippet and try out Slick’s “Single Item” demo using NVDA screen reader.

Avoid mixing incompatible ARIA roles

The first two elements in the hierarchy represent a toolbar with a tab list nested inside it. These ARIA attributes are described in the specification as follows:

  • The ARIA toolbar role represents a collection of commonly used function buttons or controls represented in compact visual form.
  • The ARIA tablist role represents a set of tab elements.

It really doesn’t make sense to have a tablist role nested inside of a toolbar role. Using the toolbar role to contain the previous and next buttons that control a carousel is fine, but it should not mix with the semantics of a set of tabs.

ARIA interfaces should be self-contained and should not mix incompatible roles together.

Note: Technically speaking, toolbar implies a grouping structure role and tablist is composite widget role. A grouping role is permitted to wrap a widget, but that does not mean that it makes sense to do so – valid does not equal semantically appropriate.

Using ARIA roles is a promise

With great power comes great responsibility. Don’t misjudge ARIA – it is powerful. But using the semantics that ARIA provides is not the end of the story. Adding ARIA roles to your HTML is a promise to code in any expected roles, states and properties for that role, as well as to implement the expected behaviours using JavaScript.

The navigation dots are implemented as a set of tabs, which would make sense for a carousel where only a single item is displayed at any one time. Any element with a tablist role should contain elements with role="tab" that reference elements that have role="tabpanel". There are no tab controls. There are no tab panels. It’s a tab list containing buttons, which is functional but not expected.

Slick’s toolbar does not implement the best practice focus management for toolbars to provide the expected keyboard behaviours (using a roving tabindex implementation).

Discrete DOM nodes are responsible for communicating accessibility information

Accessibility information coded in your HTML is conveyed by browsers to assistive technology via accessibility APIs. These APIs convey graphical user interfaces as a hierarchical tree of accessibility information similar to – but not the same as – the DOM.

For each part of an ARIA-based widget, discrete nodes in the Document Object Model (DOM) are responsible for communicating accessibility information to assistive technology. For most controls and widgets, ARIA state and property attributes relevant to a particular role need to be applied to a single HTML element that is responsible for carrying accessibility information. When multiple HTML elements need to work together to form a widget, most of the time this needs to be achieved using programmatic relationships, such as aria-describedby, aria-controls, etc.

In our accessibility testing, we often see ARIA attributes related to a particular component strewn across multiple HTML elements. This is akin to putting the required attributes of an HTML <input> element somewhere other than on that <input> element. That just doesn’t make sense, right?

Taking a look at our code snippet from Slick, we can see an ARIA state (aria-selected) and an ARIA property (aria-controls) are both separated from the element to which the attributes are related. The list item to which these ARIA attributes are applied is marked as presentational, which essentially makes it semantically the same as a <div>. This is not an appropriate location to apply these attributes.

Note: Despite the role="presentation", NVDA announces the buttons as “bullet 1 button”, “bullet 2 button”, etc.

There is a set of aria-selected attributes on the navigation dots that toggle correctly as each slide of the carousel becomes visible. However, these attributes are incorrectly applied to the containing <li> element rather than the control itself. As a result, NVDA ignores the aria-selected attributes and does not announce which of the slides is currently active. The aria-selected attribute must always be added to an element that has a role. A selected <div> makes no sense. On the other hand, a selected tab does make sense.

Note: The aria-current attribute should not be used as a substitute for aria-selected on a set of tabs.

An aria-controls attribute is primarily intended for creating a programmatic relationship between a control and the element on the page that is controlled by it. For example, a tab controls a tab panel. As with the aria-selected attributes, the aria-controls attributes in the Slick code are incorrectly applied to the containing <li> element rather than the control itself. These attributes also reference element IDs that do not exist in the page.

Avoid duplicating HTML semantics with unnecessary ARIA attributes

The <button> element in the snippet of code we’re looking at includes two unnecessary ARIA declarations: role="button" and tabindex="0".

This breaks the first rule of ARIA use – use native HTML elements whenever possible – and provides no additional benefit by being applied to the button.


HTML’s <button> element has an implicit accessibility role of button, so there is no need to duplicate this using the role attribute.

HTML <button> elements are natively keyboard focusable. Applying tabindex="0" to an element causes that element to become keyboard focusable and part of the natural focus order of the page. The only reason we may see this is if the ARIA role being used expects a single tab stop, which is implemented by using a roving tabindex. This is the expected behaviour for a set of tabs, for example, so the tabindex attribute would actually belong in this code if it was implemented correctly as a set of tabs. However, examining the behaviour in the demo, the buttons used for the navigation dots all have tabindex="0" applied and never change to tabindex="-1".

Other issues

The seasoned accessibility experts reading this may notice other issues that exist with Slick’s demos, which include:

  • An aria-live region is used to wrap the content of the carousel slides, which causes NVDA to announce the content of every carousel in some circumstances (compare NVDA running with Chrome versus Firefox).
  • Listbox widgets and role="option" attributes are used to mark up each slide, which is a misunderstood implementation of the specification, which is intended to extend HTML’s native <select> elements.
  • The aria-label attributes applied to the previous and next buttons are unnecessary as they duplicate the text content inside the <button> element that already acts to provide an accessible name.
  • Poor visibility of keyboard focus.

Aside from the issues with ARIA semantics discussed above, Slick is described as being “fully accessible with arrow key navigation”. The expected method of operating many ARIA interfaces from the keyboard is to use your keyboard’s arrow keys. However, Slick’s demo carousels do not respond to presses of the arrow keys on a keyboard.

Something I mentioned in the podcast interview with Nic is that I don’t believe there is such as thing as “fully accessible”, so I try to avoid using that phrase. It’s no easy task making something accessible to every person and accommodate the way they interact with the world. You can only do your best to make things as accessible as you can.

So, um… not a dark art, huh?

I’ve covered quite a lot in this post by only looking at a small snippet of code. This may seem daunting to many web developers reading this, but ARIA really isn’t as hard as it may seem. I hope you feel like you now understand a bit more about ARIA and how to use it appropriately.

As with any aspect of coding, it’s important to understand your tools before you use them. In the case of ARIA, my advice is:

  1. Read me first because no ARIA is better than bad ARIA.
  2. Familiarise yourself with the rules for ARIA use in Notes on ARIA Use in HTML.
  3. Practice your art forms, even the dark ones.


Thanks to Steve Faulkner for helping clarify a point about ARIA semantics… and also for turning my own confusion around ARIA into understanding many years ago.

Originally published on diginclusion.com. Updated in May 2022 to link to the new ARIA Authoring Practices Guide.