Use WAI-ARIA mark-up

Technology oriented Frontend developer

ARIA stands for Accessible Rich Internet Applications. WAI-ARIA is designed to aid in making dynamic and interactive web applications more accessible. It provides semantics and conveys updates and changes to assistive technology.

It can be used for:

  • Adding functionality that does not exist elsewhere, e.g. conveying updates to assistive technology
  • Conveying functionality that exist elsewhere, but can not be passed on to assistive technology otherwise, e.g. extend/collapse or sliders

WAI-ARIA should be not used as a bandage for poor code. 

The following will give an introduction to:

  • WAI-ARIA roles
  • WAI-ARIA states and properties
  • WAI-ARIA Live regions
  • WAI-ARIA use of tabindex

WAI-ARIA roles

Use WAI-ARIA role attributes to communicate a widgets role to assistive technology (AT). The role given by the WAI-ARIA role attribute trumps the role of the native element. The WAI-ARIA specification maintains a list of roles.

JavaScript is often used to insert custom modal dialogs (usually divs) instead of opening a new browser window. The WAI-ARIA role dialog can be used on elements used as containers for the dialog to inform screen reader users that a custom dialog is being inserted (or made visible via CSS). 

In the following example a div element has a role attribute of dialog. A dialog is an application window that is designed to interrupt the current processing of an application in order to prompt the user to enter information or require a response.

By using the role dialog and the WAI-ARIA attributes aria-labelledby and aria-descibedby on the same element, we provide additional information to AT.

1
2
3
4
5
6
7
8
<div id="myDialog" role="dialog"
     aria-labelledby="myTitle"
     aria-describedby="myDesc">
    <div id="myTitle">Save changes?</div>
    <button id="saveMe" type="button"> Yes </button>
    <button id="discardMe" type="button">No </button>
    <button id="neverMind" type="button">Cancel </button>
</div>
2-3

The aria-labelledby attribute is similar to aria-describedby in that both reference other elements to calculate a text alternative. However, a label should be concise, whereas a description is intended to provide more detailed information. Depending on the type of screen-reader that is used, the attributes aria-labelledby and aria-describedby will either be announced upon opening the dialog, or they will be available to read via the virtual cursor.

<div id="myDialog" role="dialog"
     aria-labelledby="myTitle"
     aria-describedby="myDesc">
    <div id="myTitle">Save changes?</div>
    <button id="saveMe" type="button"> Yes </button>
    <button id="discardMe" type="button">No </button>
    <button id="neverMind" type="button">Cancel </button>
</div>

This example follows the following important rules:

  1. If you use the role “dialog”, you must use aria-labelledby to point to the element containing the visible dialog title. The aria-labelledby attribute must be on the same HTML element as the role “dialog” attribute.
  2. If your dialog has one main descriptive text, you must use aria-describedby to point to its element, also on the same element that has role “dialog”.

Document landmark roles

Document landmark roles are a subset of regular roles, they are semantic extenders that provide training wheels for semantic elements that don’t exist or haven’t been adopted fully by all browsers. 

Use them to help screen reader users understand the role of a section on a page and help orientate themselves within the document. 

WAI-ARIA defines the following document landmark roles:

  • Article (content that makes sense in its own right such as a complete blog post)
  • Banner (site-orientated content, such as the title of the page and the logo)
  • Complementary (supporting content for the main content)
  • Contentinfo (information about the content)
  • Main (main content)
  • Navigation (content that contains the links to navigate this or related documents)
  • Search (contains a search form to search the site)

The following example specifies the landmark roles of banner, navigation, main and contentinfo. Landmark roles make navigation between areas of your page more efficient for different kinds of users. They help convey basic semantic intent and can serve as hooks and helpers for other technologies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<header role="banner">
   <p>Put company logo, etc. here.</p>
</header>
<nav role="navigation">
   <ul>
      <li>Put navigation here</li>
   </ul>
</nav>
<main role="main">
   <p>Put main content here.</p>
</main>
<footer role="contentinfo">
   <p>Put copyright, etc. here.</p>
</footer>
1, 9, 12

Within any document or application, the author SHOULD mark no more than one element each with the main, banner and contentinfo role.

<header role="banner">
   <p>Put company logo, etc. here.</p>
</header>
<nav role="navigation">
   <ul>
      <li>Put navigation here</li>
   </ul>
</nav>
<main role="main">
   <p>Put main content here.</p>
</main>
<footer role="contentinfo">
   <p>Put copyright, etc. here.</p>
</footer>

WARNING: The WAI-ARIA role navigation does not work well with the HTML5

States and properties

Use WAI-ARIA states and properties in combination with roles. Changes in states or properties will notify the user of an AT that a change has occurred and help understand how to interact with the widget. The state identifies a unique configuration of information for an object. For example, the aria-checked property has three state values; true, false and mixed.

In the accessible dialog example we provide extra information to the AT user by using WAI-ARIA properties aria-labelledby and aria-description. By further adding the state aria-hidden we prevent screenreaders from interacting with the rest of the page once the modal dialog is open.

1
2
3
4
5
6
7
8
<main id="mainPage" role="main"
    aria-hidden="true">
    <div id="modal" role="dialog"
         aria-hidden="false"
         aria-labelledby="modalTitle" 
         aria-describedby="modalDescription">
    </div>
</main>
2

When the modal dialog is displayed, the mainPage is marked with aria-hidden='true' to prevent screen readers from interacting with it once the modal dialog is open.

4-6

By using state aria-hidden and properties aria-labelledby and aria-describedby, we increase accessibility for the modal dialog for the AT user.

<main id="mainPage" role="main"
    aria-hidden="true">
    <div id="modal" role="dialog"
         aria-hidden="false"
         aria-labelledby="modalTitle" 
         aria-describedby="modalDescription">
    </div>
</main>

A good rule of thumb is that elements that change how they look often have changing states. The dialog changes by going from being invisible to visible . So we are going to use aria-hidden="true" on the dialog initially and change it's value when it is shown.

function showModal(obj) {
    document.getElementById('mainPage').setAttribute('aria-hidden','true'); 
    document.getElementById('modal').setAttribute('aria-hidden','false');
function showModal(obj) {
    document.getElementById('mainPage').setAttribute('aria-hidden','true'); 
    document.getElementById('modal').setAttribute('aria-hidden','false');

It is possible to use CSS selectors to show and hide the dialog based on the aria-hidden value. Then there is no need to change the CSS class in the code, only the value of aria-hidden.

[aria-hidden=true] {visibility: hidden;}
[aria-hidden=true] {visibility: hidden;}

There is a full list of states and properties to help define accessible widgets in the WAI-ARIA specification.

Live regions

WAI-ARIA is the only language capable of conveying updates to assistive technology. Live regions allow elements in a document to be announced if there are changes, without the user losing focus on their current activity.

The aria-live property has a value indicating one of three verbosity levels in a region:

  • Off: This indicates that the region is not live
  • Polite: This indicates that it is not necessary to respond until user completes their current activity
  • Assertive: This value is a higher priority than normal, but does not necessarily interrupt the user immediately

They are written as such:

<ul aria-live="off">
<ul aria-live="polite">
<ul aria-live="assertive">
<ul aria-live="off">
<ul aria-live="polite">
<ul aria-live="assertive">

Other important properties that can be used when defining live regions are:

Aria-atomic: Indicates if AT should present all or only part of the changed region to the user. It has the values true or false. If this property is set to true, AT should present the entire region as a whole.

In the following example, all elements within an unordered list will be announced in their entirety when the region is spoken, unless another element further down the chain overrides the aria-atomic property.

<ul aria-atomic="true"
    aria-live="polite">
<ul aria-atomic="true"
    aria-live="polite">

Aria-busy: Prevents AT announcing changes before the updates are complete. It has the values true or false. If multiple parts of a live region need to be loaded before changes are announced to the user, the aria-busy property can be set to true until the final part is loaded, and then set to false when the updates are complete.

<ul aria-atomic="true"
    aria-live="polite"
    aria-busy="true">
<ul aria-atomic="true"
    aria-live="polite"
    aria-busy="true">

Aria-relevant: Indicates what changes are considered relevant within a region. Accepts a space separated list of the following property values:

  • Additions: Nodes are added to the DOM within the region.
  • Removals: Nodes are removed from the DOM within the region.
  • Text: Text is added or removed from the DOM.
  • All: All of the above apply to this region.

In the absence of an explicit aria-relevant property, the default is to assume there are text changes and additions:

<ul aria-relevant="text additions">
<ul aria-relevant="text additions">

The following example would only announce changes if nodes are added to the DOM within the region. If there are text changes, or nodes are removed within the region, the user will not be notified.

<ul aria-relevant="additions"
    aria-atomic="true"
    aria-live="polite">
<ul aria-relevant="additions"
    aria-atomic="true"
    aria-live="polite">

Tabindex

The HTML tabindex attribute can be used to set tab structure on a page. Do not use tabindex as a replacement for a logical reading order. If mark-up has a logical structure you don’t need tabindex for interface elements that are already in the keyboard tab order, such as buttons, links and form elements.

WAI-ARIA extends tabindex to be: 

  • used on all visible elements
  • given focus through scripting

WAI-ARIA allows a negative value (typically -1) to be specified for elements that should not appear in the keyboard tab order, but can be programmatically focused.

Tabindex is relevant every time you want to set focus to something, not just when using script. Use it for all widgets that have a series of components that need keyboard access, such as a tree. For example a menu widget where the menu itself is in the tab order but the menu items is not. Instead the menu items could be programmed so they can be navigated using cursor keys. This way, users do not have to tab through all items in the menu, and can better navigate the document.

The following example uses a tabindex attribute value of 0 to put a

element into the tab order so that a keyboard user can navigate to the element:

<div tabindex="0">
...
</div>
<div tabindex="0">
...
</div>

The following example uses a negative tabindex attribute value, so that the element is not placed in the tab order, but can receive programmatic focus:

<a href="http://accessibilityagent.no" id="progaccess" tabindex="-1">
    42 reasons to implement accessibility
</a>
<a href="http://accessibilityagent.no" id="progaccess" tabindex="-1">
    42 reasons to implement accessibility
</a>

The following snippet of JavaScript selects the element defined above, and uses the focus method to place focus on the element:

1
2
var objDiv = document.getElementById('progaccess');
objDiv.focus();
2

Focus on the element

var objDiv = document.getElementById('progaccess');
objDiv.focus();

Related guidelines:

WCAG Guideline 4.1.2 Name, Role, Value

© 2015 Accessibilityagent (BETA) - Implementing accessibility so you can drink beer.