In Introduction to Web Accessibility and Semantic HTML, we saw how to write HTML using the proper semantic elements and attributes in order to expose element semantics to Assistive Technology (AT). However, that is only a part of the problem. These semantic techniques do not provide solutions to the now common dynamic websites. Web content that is created or updated after the page is rendered can be an issue for accessibility. The World Wide Web Consortium’s (w3c) 1999 standard, Web Content Accessibility Guidelines (WCAG) 1.0 addressed the issue of static content, the 2008 revision, WCAG 2.0 , includes guidelines and techniques that address dynamic content.
Many common issues with dynamic content can be addressed by good coding practice. The WCAG 2.0 documentation includes many techniques and best practices to help developers create more accessible dynamic web applications. Even when coded properly, however, dynamic content is not necessarily accessible. Since HTML only has native support for a few user interface controls (links and form elements), developers often create their own controls using a combination of HTML elements and script. The script changes the purpose (role) and state (properties) of the HTML elements used to build the controls, but these changes are not exposed to Assistive technology (AT). To overcome this problem a new solution evolved: Accessible Rich Internet Applications (ARIA). ARIA extends HTML with additional attributes designed to convey custom semantics. These attributes are used by browsers that ARIA to pass along the controls’ state and role to the accessibility API. The most common problems that this addresses are:
This article is an introduction to ARIA markup. You will see how “Widgets”, a term ARIA uses to describe DHTML controls, are used to make accessible custom UI such as buttons and menus. We’ll cover the use of ARIA’s “Landmark” roles for navigation and live regions for dynamic content areas.
ARIA emerged as a way to address the accessibility problem of using a markup language intended for documents, HTML, to build user interfaces (UI). HTML includes a great many features to deal with documents (P, h3,UL,TABLE) but only basic UI elements such as A, INPUT and BUTTON. Windows and other operating systems support APIs that allow AT to access the functionality of UI controls. Internet Explorer and other browsers map the native HTML elements to the accessibility API, but the html controls are not as rich as the controls common on desktop operating systems, and are not enough for modern web applications Custom controls can extend html elements to provide the rich UI needed for modern web applications. Before ARIA, the browser had no way to expose this extra richness to the accessibility API or AT. The classic example of this issue is adding a click handler to an image. It creates what appears to be a clickable button to a mouse user, but is still just an image to a keyboard or AT user.
The solution was to create a set of attributes that allow developers to extend HTML with UI semantics. The ARIA term for a group of HTML elements that have custom functionality and use ARIA attributes to map these functions to accessibility APIs is a “Widget”, and we will talk much about widgets. ARIA also provides a means for authors to document the role of content itself, which in turn, allows AT to construct alternate navigation mechanisms for the content that are much easier to use than reading the full text or only iterating over a list of the links.
In this introduction we will cover ARIA widgets and navigation at a high level. It is important to remember that in simple cases, it is much preferred to use native HTML controls and style them rather than using ARIA. That is don’t reinvent wheels, or checkboxes, if you don’t have to.
We will also have a quick example of how to apply ARIA to an existing DHTML control. Fortunately, ARIA markup can be added to existing sites without changing the behavior for mainstream users. This greatly reduces the cost of modifying and testing the website or application.
ARIA leverages the existing tabindex property from HTML and extends its use. In HTML 4.0 tabindex could only be set for a few elements and could only have positive values. ARIA extends this to allow any visible element to be assigned a tabindex. It also allows for the value -1 to be set which takes the element out of the tab order altogether while still allowing programmatic focus.
Together, this allows us to create better navigation experiences for the user. Consider, for example, the case of a complex drop menu, where each top level menu item contains dozens of. Having to tab through every child menu item is tedious and time-consuming for keyboard users. We can avoid this by setting the tabindex of these children to -1, making the tab order only include the menu titles. We can use arrow keys or other common navigation paradigms to work with the child menu items, using the aria-expanded or aria-haspopup properties, together with menu role to communicate this functionality to AT.
A quick example of what ARIA adds and how it does this is in order. Consider an image used to invoke some action:
<img src=“mybutton.gif” onclick=“doSomething();”>
This has many accessibility problems: no keyboard focus, no keyboard interaction, MSAA role is graphic and the name is null, which many screen-readers will read as the fully-qualified URL of the image. A keyboard user will not be able to focus on or invoke this control, and AT users will have no indication of what the control does. Using ARIA we can correct for these issues:
<img tabindex=0 onkeypress=“doSomething();” role=“button” alt=“Do Something” src=“mybutton.gif” onclick=“doSomething();”/>
We address the keyboard issues by adding tabindex and keyPress attributes. Now the button is able to be invoked, but to assistive technologies (AT) it still seems to be merely an image with no name. The role attribute is the answer here; it assigns an ARIA role to the control which gets mapped to MSAA role and UIA control type, with the value of the @alt attribute (sometimes called “alt text”) as its name. Now AT users will be presented with a button named “Do Something” and they will be able to invoke or ‘press’ the button.
Native HTML semantics should be used where possible, e.g. <button> in this case. So ARIA would be inappropriate in a case a simple as this. The following examples will be more complex, but build on this simple concept to illustrate the use of ARIA to document complex user interfaces that are not natively supported in HTML.
We will use a technique of ‘progressive enhancement’, or adding complex UI functions on top of valid HTML. We do this so that the content ‘gets better’ with ARIA but still works for legacy browsers.
Elements can be extended with the ROLE attribute to document the purpose of the control. This is done at the top level of the controls hierarchy, or “widget”, to document the control itself and at the child level to document the purpose of sub elements.
<ul role="tree"> <li><a role="treeitem" aria-expanded="false" ><img src=" p.png" alt="+" />Documents</a> <ul role="group"> <li role="presentation"><a role="treeitem" href="File1.htm">File 1</a></li> <li role="presentation"><a role="treeitem" href="File2.htm">File 2</a></li> <li role="presentation"><a role="treeitem" href="File3.htm">File 3</a></li> </ul> </li> </ul>
Here we see a simple expandable tree view (script omitted for brevity) that exposes its role of “tree” and its children as “treeitem”, “group” and “presentation”.The role values can represent both a mapping to control types, for API, and the purpose or intent of the element such as grouping and presenting other content.Role is used quite flexibly in ARIA as we will see with landmarks soon.
Generally the top level element should be mapped to a common control type for complex controls such as tree, slider or dialog. Sub elements may be control types themselves, as in tabbed dialogs, may be sub types such as menuitem, or may only have a general purpose such as grouping.ARIA has attempted to provide a comprehensive list of possible roles to choose from.The full list of role definitions can be found at the W3C.
With the ARIA role we have a means of presenting what a control is, or can do, but no way of presenting what it is doing.ARIA uses a set of extended attributes to document the State and Properties of elements within the control.Some properties can be set for any element some are intended for elements of specific types and their children.For example the aria-expanded property is expected for treeitems, as seen in the previous example, but would make little sense on a button.
States and properties can serve two purposes.First they convey to the browser what the controls state is, allowing the browser to send this along to the accessibility API.Scripts can also make use of the aria role, states, and properties rather than custom attributes or other mechanisms to manage the state and behavior of the custom control.
For example, instead of hand coding the popup behavior for a sub-menu directly, we could have code that finds widgets with menu roles, looks for aria-haspopup on menuitem children, and dynamically adds the event handlers to the appropriate aria-labeledby child.
ARIA properties offer features not supported in HTML.They allow us to add semantic information into the markup; they document the ‘why’ of the controls.Checkbox is a good example.The ARIA checkbox is a tri-state checkbox, supporting checked, unchecked and mixed, while the HTML checkbox is two-state, supporting only checked and unchecked.If the native functionality is sufficient it is much less work, and better practice, to use it.But when we need functionality beyond HTML’s native controls ARIA allows us to create it and convey the what, how and why of it to AT.
Sometimes it is not functionality we are adding but simply look and feel.If we want a prettier checkbox, or one a windowless checkbox that works better with other DHTML controls, we must construct our own.With ARIA we do not need to exclude users with disabilities to achieve the look and feel we want for our sites.
In addition to roles that convey the control type of a widget or the type of behavior for an element, ARIA also has “Landmark” roles that are used to convey the type or purpose of content.
Landmark roles are intended to improve the experience of navigating content. They are addressing the problem that AT faces in navigating a site. Instead of having to listen to or tab through every element in the page’s navigation bars, advertising, etc., AT users can navigate directly to the section they want. Before ARIA this was often handled with “skip links,” a link at the top of the page that jumped to the main content or other often used parts of the page. Skip links are less than ideal, because they can interfere with the visual layout of the page, and be confusing to sighted users.. By providing a common set of semantics for specifying page and site navigation, ARIA allows authors and developers to document the different types of content on the page, so that AT can provide a way for users to navigate quickly to that content. The same role attribute is used as before, we simply use a different set of values.
Rather than specify a DIV to be a control type, such as a button, we specify its content type, such as “main” or “search”. This exposes to AT that this content is a landmark, meaning a logical chunk of the page’s content, and what type of content it is. This is used by AT to create enhanced navigation experiences. For example, a screen reader could provide a keyboard shortcut to cycle through the landmarks on a page, reading out the role of each.
The landmark roles are:
A full list of content roles may be found on the W3C.
Applications tend not to be static. An email application that doesn’t update when mail is received would not be very useful. But AT doesn’t know what to do when a new chunk of HTML is added to the DOM. A sighted user might see a new row added to their inbox and see that it is a new mail, but without contextual and semantic attributes AT cannot know this. ARIA calls these updatable content areas Live Regions.
Live regions are elements that are expected to get updates at runtime. These will typically be divs, tables, etc. that naturally hold content. For the email application mentioned above we might have a DIV that contains child DIVs in a microformat for mail headers. By setting the parent DIV’s role to “log” AT knows to ‘watch’ for new children and voice them to the user.
An element may be set as an ARIA live region in two ways. An ARIA role may be set on the element that is a live region role: alert, status, timer, marquee or log. This indicates to AT not only that this element will be updating, but also conveys the semantic type of the region. If the element is not one of the explicit live region types then the aria-live attribute may be used.
In the first case the verbosity of the live region will be inferred from the role, in the second case it will be the value of the attribute: assertive|polite|off. The aria-live attribute may be added to any element.
When using live regions the first step is to identify what parts of the page will be dynamically updated. Of those identify which ones are native ARIA live region types and the priority of each areas updates.
The trigger and scope of the updates must be specified as well. Decide how much context is needed. If you want the whole live region read, use aria-atomic=true. Then decide what types of changes to announce: aria-relevant=“additions removals text” (space separated list, default is additions removals). The W3C provides examples of using live regions.
Let’s go beyond a simple button to a common DHTML use case: the dynamic menu. These have been constructed using <ul> or <div> elements historically. Accessibility advocates have argued for using the <UL> element as many AT ‘know’ of this usage and assume these to be menus, creating alternate navigation modes for the user. With ARIA we can safely use either element as the ARIA attributes document the semantics more concretely that the tags can. We will have a full example and discussion of constructing a menu using <UL> elements in a later article. For now let’s look at a simple example using <DIV> elements as we might find it today and how we can add ARIA onto the existing code.
The typical fly out menu goes something like this:
<div id="menuBarMain"> <div id="Menu1"><a href=”#”>one</a></div> <div id=”Menu1Popup”> <div><a href=”#”>a</a></div> <div><a href=”#”>b</a></div> <div><a href=”#”>c</a></div> </div> <div id="Menu2"><a href=”#”>two</a></div> <div id=”Menu2Popup”> <div><a href=”#”>a</a></div> <div><a href=”#”>b</a></div> </div> </div>
The <div>’s are positioned using CSS and script hides and shows child menus in response to keyboard and mouse activity. The problem is that this legacy approach doesn’t push information into the accessibility API where they are available to everyone.
This is the crux of what ARIA provides authors. By managing the ARIA properties we can directly affect the values presented via APIs. The essential tasks when building ARIA widget are then to document the roles, specify the initial properties, and marshal state changes for these properties into AAPI by managing the ARIA properties at runtime.
Let’s look at the ARIA properties we need to add to our menu example:
<div id="menuBarMain" role="menubar">
We add the menubar role to the outer container, telling AT that we intend the following to be a top level menu, or list of menus.
<div role="menuitem" aria-haspopup="true" id="Menu1"> <a href=”#”>one</a> </div>
The top level item gets a menuitem role and we tell AT that there is a popup menu controlled by this menu item.
<div role="menu" aria-labelledby="Menu1" aria-hidden="true">
The popup menu itself gets a menu role, we set it as labeled by the Menu1 div and set its initial state to hidden. Note that we no longer need to track it by ID as we can use ARIA methods to parse the menu tree.
<div role="menuitem"><a href=”#”>a</a></div> <div role="menuitem"><a href=”#”>b</a></div> <div role="menuitem"><a href=”#”>c</a></div> </div> <div role="menuitem" aria-haspopup="true" id="Menu2"><a href=”#”>two</a></div> <div role="menu" aria-labelledby="Menu2" aria-hidden="true"> <div role="menuitem"><a href=”#”>a</a></div> <div role="menuitem"><a href=”#”>b</a></div> </div> </div>
<script> // toggle code omitted for brevity menu.setAttribute("aria-hidden", true); </script>
Here we merely keep the aria-hidden property in sync with the menu’s state. We will see in further examples how we can synchronize other properties and leverage ARIA to maintain the control’s state.
This is only a very brief illustration of how and where ARIA attributes would be added. Issues about how to preserve the widgets state, or even hook our toggle method, are beyond the scope of an introduction.
The important thing to take away from this example is that ARIA allows more than merely documenting the role of a custom control via the role attribute; it allows us to expose the properties and states of the controls via accessibility API to the user, that is it allows us to interoperate with these API from script by managing the various ARIA attributes.