Coding on a laptop

Intro to Advanced ARIA

This is the first post in Harris Schneiderman’s Advanced ARIA series. In this series, he’ll explain how to create accessible widgets and structures using ARIA, with practical tips and real working examples.

Nearly a quarter of a century has passed since HTML was first released. To say we’ve come a long way in terms how web content functions would be an understatement; content was primarily static back then.

Content today is dynamic, and can’t always be supported by native HTML elements – especially when it comes to accessibility. In modern web applications, ARIA has become essential in making complex and dynamic widgets accessible. In this Advanced ARIA series, I’m going to take you on a deep dive into advanced ARIA – and how to use it to create complex accessible widgets and structures. I’m also going to provide some working examples of how to create accessible content using ARIA.  Some examples of the things we’ll get into in this first post:

  • A refresher on what ARIA does, and how it is used to create accessible web content
  • ARIA best practices
  • Challenging situations, and what you can do to work through them

Without further ado, let’s get started.

ARIA: A Refresher

Accessible Rich Internet Applications, or ARIA, is a technical specification that provides an attributes framework geared towards making web components accessible.  With ARIA, we can provided simple attributes that are consumable by assistive technologies to convey information about widgets, structures, and behaviors.  It’s important to remember that it is always better to use native HTML elements instead of their ARIA counterparts. That is, use a button type=”button” instead of div role=”button”.

ARIA attributes can be broken down into three categories: roles, states and properties. Let’s take a look at these categories.

Roles

Roles are attributes that convey information about what an element is. For instance, role=”checkbox” will inform AT that the element is a checkbox.  Other roles include: “alert”, “dialog”, “progressbar”, “log”, “radio”, “slider” and many more.

States

States are attributes that convey the current state of an element.  For example, aria-checked=”true” will inform AT that a checkbox is currently in the checked state.  Other state attributes include: “aria-expanded”, “aria-invalid”, “aria-pressed”, “aria-valuenow”, “aria-sort”, etc.

Properties

Properties are essential attributes that describe the nature of the element.  Properties are very similar to states, the only difference being properties are far less likely to be dynamically updated.   For example, aria-label=”Terms and conditions” will inform AT of the element’s accessible label “Terms and conditions”.  Some other examples of property attributes include: “aria-labelledby”, “aria-describedby”, “aria-controls”, “aria-owns”, and “aria-posinset”.

ARIA and A11Y

In the real world, many websites are not designed with accessibility in mind. Luckily, in these cases, ARIA can really help save the day.  Take the HTML markup below as an example of poorly coded button and link elements designed without accessibility considerations:

<div class="button">Close</div>


<span class="link" onclick="location.href='/home'">Home</span>

There are a couple problems with this markup:

  • There is nothing in place to let a screen reader know what these elements are (their roles)
  • Keyboard users will not be able to interact with these controls (neither focusable nor activatable with a keyboard)

ARIA to the Rescue

As I’ve already mentioned, it’s best to just use native button and a elements in this situation because native button and anchor elements are focusable and keyboard-activatable by default. However, in some cases, whether it’s that your manager doesn’t have to budget or resources to completely rewrite content, or your designer refuses to allow a change in HTML tag structure/CSS rule declaration, ARIA and JavaScript can provide a very quick and easy fix.

The Fix

Adding the “button” and “link” roles will let screen reader users know what these elements are.  In addition, adding tabindex=”0″ to both elements will allow keyboard users to focus these elements.  The last step is to make them activatable with a keyboard which consists of very simple JavaScript event listeners that mimic behavior of native button and anchor elements.  This means that the button element needs to be activatable with the Enter or Spacebar keys and the anchor needs to be activatable with the Enter key.

<div role="button" tabindex="0" class="button">Close</div>


<span role="link" tabindex="0" class="link" onclick="location.href='/home'">Home</span>
button.addEventListener('keydown', function (e) {
  // if ENTER or SPACE was pressed
  if (e.which === 13 || e.which === 32) {
    e.preventDefault();
    e.target.click();
  }
});

link.addEventListener('keydown', function (e) {
  // if ENTER was pressed
  if (e.which === 13) {
    e.target.click();
  }
});

ARIA Best Practices

Let’s go over some additional examples of when it is better to use native HTML elements over ARIA roles.

Headings

Headings can be implemented using the native h1 – h6 HTML elements, but the same information can be conveyed to assistive technologies using the “heading” role and the aria-level attribute.

<h2>I am a heading level 2</h2>


<div role="heading" aria-level="2">I am also a heading level 2</div>



Lists

Lists can be implemented using the native ul and li HTML elements but can also be implemented using the “list” and “listitem” roles properly.

<ul> 
    

<li>One</li>


<li>Two</li>


</ul>


<div role="list">

<div role="listitem">One</div>


<div role="listitem">Two</div>


</div>


Radio Buttons

Radio buttons can be implemented using the native input type=”radio” elements but role=”radio” (in addition to managing tabindex) can accomplish the same goal.  Keep in mind for components like radio groups, without using the native elements, JavaScript will have to be used to mimic native behavior (arrow keys cycling through the radio buttons in the group).

<fieldset>

<legend>Favorite Food</legend>


    <label for="pasta">Pasta</label>
    <input id="pasta" name="food" type="radio" />
    <label for="pizza">Pizza</label>
    <input id="pizza" name="food" type="radio" />
</fieldset>



<div role="radiogroup" aria-labelledby="group-label">

<h2 id="group-label">Favorite Food</h2>


<div id="pasta-label">Pasta</div>


<div tabindex="0" role="radio" aria-labelledby="pasta-label"></div>


<div id="pizza-label">Pizza</div>


<div tabindex="-1" role="radio" aria-labelledby="pizza-label"></div>


</div>


Challenging Situations

Complex web content can introduce some very challenging situations.  For instance, dynamic content that updates remote parts of the page or even interactive widgets that alter the state of their components.  In addition, custom widgets such as datepickers or carousels can be very difficult to implement because there are no ARIA attributes specific to the components that make a datepicker.  Thanks to ARIA and JavaScript all of these challenges can be conquered!

Things to Remember

Every component in a web application must convey its roles, states and properties so assistive technologies can consume that information.  In addition, keyboard/touch operability, color contrast, and following the spec according to the role in regards to keyboard functionality and attribute management. I find it extremely useful to follow the W3c “Custom Control Accessible Development Checklist”.

Stay tuned for my next post in the series, where I’ll talk more in depth about Live Regions and a keyboard accessible sort widget I like to call Dragon Drop.

photo of Harris Schneiderman

About Harris Schneiderman

Harris Schneiderman is a web developer with a strong passion for digital equality. He works at Deque Systems as the Senior Product Manager of axe DevTools building awesome web applications. He wrote Cauldron (Deque's pattern library), Dragon Drop, and is the lead developer on axe DevTools Pro. When he is not at work, he still finds time to contribute to numerous open source projects.