ARIA is a W3C specification that can be used to dramatically improve the accessibility of custom widgets, especially for users of screen readers. This talk provides practical tips and design patterns for using ARIA to create accessible user interfaces that work across all of the various combinations of browsers and screen readers that support ARIA. Additionally, this talk will focus on the tools and methodologies developers need to test ARIA in order to ensure the best possible user experience.
3. Screen Readers
Read the code (HTML)
Read the focused element
What is read:
Element/Control type
Label
Properties
State changes
4. Demo
http://youtu.be/ZnlvBIfTQfI
Demo of interacting with a checkbox using VoiceOver—the screen reader for the Mac. Notice how VoiceOver announces the control type (“checkbox”), the label (“Send me offers”), and the
current state (“checked” and “not checked”).
All this text is announced to ensure that users of screen readers can perceive and operate the widget.
5. Demo
http://youtu.be/ZnlvBIfTQfI
Demo of interacting with a checkbox using VoiceOver—the screen reader for the Mac. Notice how VoiceOver announces the control type (“checkbox”), the label (“Send me offers”), and the
current state (“checked” and “not checked”).
All this text is announced to ensure that users of screen readers can perceive and operate the widget.
6. Widgets Break
That's the experience for existing widgets. But often custom widgets don’t work this well with screen readers.
7. See Hear
For custom controls, most often problems are caused when there is a gap between the visual and audio user experience such that users of screen readers do not have access to the same
information as sighted users.
10. You Forgot
Often this is because either you forgot to use the right, most semantic markup for the job.
11. You Are Limited
<dialog></dialog>
<div class="dialog"></div>
Or, reason #2: You are limited by the expressiveness of HTML. For example, ideally you’d declare a dialog using a <dialog> tag, but for lack of one you use a <div> with a class of “dialog”.
12. To understand ARIA widgets, let’s begin with an audit of how existing HTML form controls work.
13. Widget Types
<select>
<textarea>
<input>
<button>
In HTML, a widget’s type is control by the tag name.
14. Widget Labels
<label for="gender">Gender</label>
<select id="gender">
In HTML you help the user distinguish one widget from another by providing a unique label using the <label> element.
15. <select multiple>
HTML form controls also have properties that can be used to configure their behavior. For example, a listbox can be configured to support multiple selection using the “multiple” attribute.
16. Widget Properties
<textarea readonly>
<input type="text" maxlength="100">
<input type="button" value="Submit">
Most HTML form controls have associated properties for configuring their behavior.
17. <select id="gender">
<option value="m" selected>Male</option>
Lastly, HTML form controls have states. For example, an option in a listbox can be declared selected using the “selected” attribute.
18. Widget States
<input type="checkbox" checked>
<input type="button" disabled>
Most HTML form controls have associated properties for configuring their state. Some of theses states, like checked, are managed for you by the browser—updated automatically in
response to user interaction. Others, like disabled, are not.
19. Widgets
• Types (e.g. textbox, checkbox, button)
• Labels (distinguish one instance from another)
• Properties (e.g. readonly, multi-selectable, value)
• States (e.g. selected, checked, disabled)
So, there you have it. HTML form controls have types, labels, properties and states.
20. Accessible Info
• Types
• Labels
• Properties
• States
And as we know from the checkbox demonstration at the beginning of this presentation, all of these various pieces of information are what the screen reader announces to the user.
21. See Hear
The goal being to ensure little, or no gap in what sighted users see, and what users of screen readers hear.
22. Modern web applications often require more widgets than what is provided natively in HTML. For example: tree controls, popup menus, listviews, tabviews, etc.
24. <menu>
<menuitem shortcut="N">Email</menuitem>
<menuitem shortcut="I">Instant Message</menuitem>
<menuitem shortcut="T">SMS</menuitem>
</menu>
In the future HTML will (hopefully) provide native semantics and functionality for all of the widgets we need. For example, we’ll have new tags for all of the various widget types like menus,
trees, tabs, etc.
25. <menu hidden>
And we’ll have attributes for state. For example, we’ll be able to declare menu has hidden using the “hidden” attribute.
27. YOU ARE HERE
But currently, depending on the browser and device you are supporting, you find yourself in the middle: robust support for HTML 4.01 with emerging support for HTML 5 controls.
28. Go Native?
Native widget works as expected?
Native widget is accessible?
Browser and platform constraints?
Native supports required style and
behavior customizations?
And so every developer is faced with the decision of whether or not to use a native HTML 5 control. There are many factors to consider.
29. <menu>
<menuitem shortcut="N">Email</menuitem>
<menuitem shortcut="I">Instant Message</menuitem>
<menuitem shortcut="T">SMS</menuitem>
</menu>
<div class="optionMenu">
<ul>
<li><a href="#">Email<em>N</em></a></li>
<li><a href="#">Instant Message<em>I</em></a></li>
<li><a href="#">SMS<em>T</em></a></li>
</ul>
</div>
Often, due to lack of native semantics, we build widgets by falling back to using structural HTML 4 and declaring types, properties and state
using class.
32. Problems
• HTML 4 structural elements don't
convey interactivity
• HTML 4 structural elements don't have
states
• State information is often stored in
class attribute
• States in class attributes are not
standardized
However, our current strategy often results in custom controls being inaccessible to users of screen readers. Primarily because we use class to declare everything—from type to state. And
every developer chooses different class names.
33. No Standardization
<div class="menu">
<div class="optionMenu">
<li class="selected"><a href="#">Email<em>N</em></a></li>
<li class="sel"><a href="#">Email<em>N</em></a></li>
For example, one developer might declare a menu using the “menu” class, while another might use “optionMenu”.
34. Problems
• HTML 4 structural elements don't
convey interactivity
• HTML 4 structural elements don't have
states
• State information is often stored in
class attribute
• States in class attributes are not
standardized
If there were standardization browsers might be able to actually infer meaning from the markup and send that information back to the accessibility APIs used by screen readers so that they
could notify users of the important pieces of information—control type, properties, state.
36. + ARIA
This is the core value of ARIA: ARIA provides additional semantics beyond what is available in current implementations of HTML. As the spec indicates, it’s a bridging technology—filling
gaps between versions of the HTML specs. You can use ARIA with existing HTML 4.01.
38. <menu>
<menuitem shortcut="N">Email</menuitem>
<menuitem shortcut="I">Instant Message</menuitem>
<menuitem shortcut="T">SMS</menuitem>
</menu>
<ul role="menu">
<li role="menuitem">Email<em>N</em></li>
<li role="menuitem">Instant Message<em>I</em></li>
<li role="menuitem">SMS<em>T</em></li>
</ul>
For example, while current versions of HTML don’t yet define semantics for declaring menus, we can use ARIA to fill the gap.
39. ARIA is well supported across all of the major browsers.
40. Three Types of ARIA Attributes
• Roles (Control/Widget Type - e.g. menu, tab, etc.)
• Properties (e.g. label, or has a popup menu)
• States (e.g. hidden, or selected)
41. Setting the role Attribute
<ul role="menu">
// Native DOM
node.setAttribute("role", "menu");
// jQuery
node.attr("role" "menu");
// YUI
node.set("role" "menu");
The role attribute can be declared in markup, or set programmatically using JavaScript.
42. Definitive Number of Roles
<div role="popupmenu">
<div role="superslider">
<div role="window">
Like the <input> element’s type attribute, the ARIA role attribute can only be set to one of several predefined values.
43. Definitive Number of Roles
<div role="popupmenu">
<div role="superslider">
<div role="window">
50. Setting ARIA Properties
<a role="button" aria-haspopup="true" />
Properties allow you to communicate aspects of a control, for example: that a menu item has a popup menu.
ARIA properties are always prefixed with "aria-".
51. Setting ARIA Properties
node.setAttribute("aria-haspopup", true);
Properties allow you to communicate aspects of a control, for example: that a menu item has a popup menu.
ARIA properties are always prefixed with "aria-".
53. Setting ARIA States
<li role="menuitem" aria-disabled="true" />
ARIA states are used to communicate widget state information you are likely already maintaining in a widget class and rendering back to the view via markup and CSS.
54. Setting ARIA States
node.setAttribute("aria-disabled", true);
ARIA states are used to communicate widget state information you are likely already maintaining in a widget class and rendering back to the view via markup and CSS.
56. Native vs. ARIA
<select>
<ul role="listbox">
<select multiple>
<ul role="listbox" aria-multiselectable="true">
<option selected>
<li role="option" aria-selected="true">
When compared alongside native semantics, ARIA attributes look and feel less alien. For example, I like to think of ARIA roles as “tags in attribute form”. And ARIA attributes are just like
native attributes, just with an “aria-” prefix.
57. Using roles, states, and properties
• Set via JavaScript using setAttribute()
• Remember properties and states require "aria-" prefix
node.setAttribute("aria-hidden", false);
node.setAttribute("aria-haspopup", true);
• Definitive number of roles, states and properties
• ARIA trumps existing semantics
60. <ul role="tablist">
<li role="tab" />
<li role="tab" aria-selected="true"/>
<li role="tab" />
<li role="tab" />
</ul>
In the interest of Progressive Enhancement, when building custom widgets always start with the closest native semantics and supplement with ARIA
63. Styling Roles, States and Properties
a:focus {
}
a:active {
}
a:hover {
}
button[disabled] {
background: ...;
}
For native HTML form controls, CSS enables the styling of states using pseudo classes and attributes selectors.
64. Styling Roles, States and Properties
.menu.hidden {
}
.menuitem.selected {
}
.menuitem.disabled {
}
For custom widgets, developers have typically used class names.
65. Styling Roles, States and Properties
ul[role=menu] {
}
button[aria-haspopup] {
background: ...;
}
li[aria-disabled=true] {
color: #ccc;
}
ul[aria-hidden=true] {
display: none;
}
Since ARIA uses attributes, ideally we could simply leverage attribute selectors for styling ARIA widget types, and states.
66. Styling Roles, States and Properties
ul[role=menu] {
}
button[aria-haspopup] {
background: ...;
}
li[aria-disabled] {
color: #ccc;
}
ul[aria-hidden] {
display: none;
}
For ARIA attributes that accept a boolean, we can make the CSS even more terse by just testing the presence of the attribute.
67. Styling Roles, States and Properties
li[aria-disabled] {
color: #ccc;
}
ul[aria-hidden] {
display: none;
}
// Set disabled
node.setAttribute('aria-disabled', true);
// Unset disabled
node.removeAttribute('aria-disabled');
We’d set the attributes using setAttribute(), and unset them using removeAttribute().
68. However, if you need to support older IEs (6 & 7) this won’t work. IE 6 doesn’t provide support for attribute selectors. Additionally, IE 7 supports attribute selectors, but when attributes are set
using setAttribute() they don’t trigger the change in style expressed in CSS.
69. Styling Roles, States and Properties
// Semantically express state
node.setAttribute('aria-disabled', true);
// Style state
node.addClass('disabled');
So, if you need to support older versions of IE you need to touch the DOM twice for every state update: once to set the ARIA role (to ensure the state change is communicated to users of
screen readers), another time to set the class for visual style.
71. For example, all widgets need to be labeled, but sometimes the visual design doesn’t call for the label.
72. Label Composite Widgets
<h2 class="offscreen">System Folders</h2>
<ul role="listbox">
<li role="option">Inbox</li>
<li role="option">Drafts</li>
</ul>
<h2>Personal Folders</h2>
<ul role="listbox">
<li role="option">Folder 1</li>
<li role="option">Folder 2</li>
</ul>
Historically we’ve solved this problem by just hiding the label off screen using CSS.
73. Label Composite Widgets
<ul role="listbox" aria-label="System Folders">
<li role="option">Inbox</li>
<li role="option">Drafts</li>
</ul>
<h2 id="folders">Personal Folders</h2>
<ul role="listbox" aria-labelledby="folders">
<li role="option">Folder 1</li>
<li role="option">Folder 2</li>
</ul>
ARIA provides two new methods for labeling widgets:
1. The “aria-label” attribute allows you to specify a label that is not rendered visually.
2. The “aria-labelledby” attribute allows you to use the text of another element in the DOM as the label.
74. The aria-describedby Property
node.setAttribute("aria-describedby", "[node_id]");
Additionally, ARIA provides the "aria-describedby" attribute which enables you to provide the id of the element whose text supplies a longer description for a widget.
75. One of the most straightfoward uses of the "aria-described" attribute is for alert dialogs.
76. <div role="alertdialog" aria-labelledby="hd"
aria-describedby="msg">
<div id="hd">Confirm Close</div>
<p id="msg">Your message has not been sent. Do you want to
save it in your Drafts folder?</p>
<div>
<button>Save to Drafts</button>
<button>Don't Save</button>
<button>Keep Writing</button>
</div>
</div>
For alert dialog widgets, use the “aria-describedby” attribute to specifying the message the dialog contains.
77. The aria-describedby Property
<div id="description" class="hidden">
Press Ctrl + [, or Ctrl + ] to switch tabs.
</div>
<ul role="tablist" aria-describedby="description">
Another use case for “aria-describedby” would be if you want to provide additional instructional/tutor text for users of screen readers. For example, to alert users of the keyboard shortcuts
available for operating a widget.
78. The aria-describedby Property
var description = document.createElement("div");
description.id = "description";
// Hide off screen via CSS
description.className = "hidden";
document.body.appendChild(description);
tabView.setAttribute("aria-describedby", "description");
Since the “aria-describedby” attribute takes an id, you often need to hide the element containing description off screen using CSS.
79. .element-invisible {
position: absolute !important;
height: 1px; width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}
http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
My current, preferred method of hiding content that still needs to be accessible to users of screen readers.
81. Repairing Nesting
<div role="menu">
<ul>
<li role="menuitem">
<li role="menuitem">
<li role="menuitem">
</ul>
</div>
ARIA widgets require a direct parent-child relationship. Nodes between elements with the declared ARIA roles can result in problems for the end user.
83. Repairing Nesting
<div role="menu">
<ul role="presentation">
<li role="menuitem">
<li role="menuitem">
<li role="menuitem">
</ul>
</div>
This is correctable by using the ARIA “presentation” roles to hide these intermediary nodes, thus restoring a direct parent-child relationship.
86. Not providing the expected keyboard shortcuts for ARIA widgets is analogous to building a car and not adding the steering wheel.
87. If you implement keyboard shortcuts, you need to make sure that you implement the right ones. Otherwise it would be like getting in a car, and finding a joystick instead of a steering wheel.
88. Widget Keyboard Patterns
Task Key
Focus Next or Previous Tab / Shift + Tab / Arrows
Change selection →, ←, ↑, ↓
Expand / Collapse →, ←, ↑, ↓
Exit Esc
Click Spacebar
Default Action Enter
Implementing keyboard navigation across all of the various widget types involves handling a very few number of keys.
90. Screen Readers
Read the code (HTML)
Read the focused element
What is read:
Element/Control type
Label
Properties
State changes
To understand the value of live regions, let’s revisit the fundamentals of how screen readers have traditionally worked: they read the currently focused element.
91. In modern web apps often parts of the UI are continually updated asynchronously. For example, on Twitter the top of the timeline will update to notify you when new tweets have arrived. This
information will go unnoticed by users of screen readers unless the user manually moves focus to this region of the page.
It is this category of problem that ARIA live regions aim to solve.
92. Live Twitter Hack
<div class="stream home-stream" aria-live="polite">
<div class="stream-item">
<div class="new-tweets-bar js-new-tweets-bar">
1 new Tweet
</div>
</div>
</div>
ARIA live regions enable developers to communicate to the screen reader that a region of the page will be dynamically updated. When that update occurs the change will be announced to
the user, even if they are focused on another control on the page.
You can try this yourself using the DOM inspector to set the “aria-live” attribute on the timeline in Twitter.
93. Live Region Use Cases
• Involuntary asynchronous updates
• Progress indicators
• Speaking instructions to the user
94. ARIA Live Regions
<div id="region" aria-live="polite"></div>
• polite
• assertive
• off
The “aria-live” attribute accepts three values. “polite” indicates the change should be communicated when the user ceases to be busy, “assertive” that the change should be announced as
soon as possible.
Any element can be made into a live region by adding the “aria-polite” attribute.
95. ARIA Live Regions
<div id="region" aria-relevant="additions">
• additions*
• removals
• text*
• all
(additions removals text)
*default values
Developers can control what type of information is announced using the “aria-relevant” attribute.
96. Roles that are live regions by default
• alert
• status
• timer
• marquee
• log
Some ARIA roles are live regions by default, and don’t require the use of the “aria-live” attribute.
97. <div aria-live="polite">
<p>hey - let me know
when you are available.
i'd like to discuss a fix
with you</p>
</div>
conversation.appendChild(message);
A browser-based messenger application is the perfect use case for ARIA live regions. For example, a user sends someone a message.
98. <div aria-live="polite">
<p>hey - let me know
when you are available.
i'd like to discuss a fix
with you</p>
<p>thanks</p>
</div>
conversation.appendChild(message);
Then appends another line.
99. <div aria-live="polite">
<p>hey - let me know
when you are available.
i'd like to discuss a fix
with you</p>
<p>thanks</p>
<p>yt?</p>
</div>
conversation.appendChild(message);
With each update, the recipient would hear the text being appended to the conversation, even though he/she might not have focus on it at the time.
100. msgList.innerHTML = messages;
Often regions of the DOM are updated using innerHTML. If these regions are ARIA live regions, the screen read won’t be able to distinguish the delta of the change between the old and new
data and will just begin announcing the entire change.
101. msgList.setAttribute("aria-live", "polite");
msgList.innerHTML = "Sorting Messages";
...
msgList.innerHTML = "Sorting Complete";
msgList.setAttribute("aria-live", "off");
msgList.innerHTML = messages;
msgList.one('.list-view-item').focus();
This slide illustrates how we used a live region to notify users of screen reader of updates to the message list in Yahoo! Mail. Before we write the new HTML into the message list, we first
replace it with some user-friendly help text. Then we toggle the live region off so as not to trigger a the announcement of the entire contents of the message list when we change the
innerHTML. Lastly, when the redraw is complete, we simply focus the first message in the list to let the user know it they can resume interacting with the control.
102. Y! Search Suggest uses a live region to create a console that outputs instructions to the user as they are interacting with the control.
103. Y! Search Suggest uses a live region to create a console that outputs instructions to the user as they are interacting with the control.
104. ARIA Live Regions
var region = document.createElement("div");
region.setAttribute("aria-live", "polite");
document.body.appendChild(region);
...
var message = document.createElement("p");
message.innerHTML = "Search suggestions are...";
// Remove previous message
region.innerHTML = "";
// Append new message to be announced
region.appendChild(message);
105. Review
Create a Live Region
Use "aria-live" or one of the Live Region roles
Control when text is spoken
Set "aria-live" to desired value
Control what is spoken
Set "aria-relevant" to desired value
106. Code
https://gist.github.com/kloots
Working examples of ARIA widgets can be found on my github account.