Improving Accessibility Through Focus Management
February 23, 2009 at 10:05 am by Todd Kloots | In Accessibility, Development | 7 CommentsA core requirement for developers using ARIA is to provide keyboard access for widgets, as users of screen readers rely on the keyboard to navigate web sites and applications. A large part of providing keyboard access is managing focus of a widget’s descendants (e.g., buttons in a toolbar, tabs in a tablist, menuitems in a menu, etc.), and the W3C guidelines provide two different approaches for doing so. This article explains both approaches and provides some practical advice for choosing between them.
The Benefit of Focus Management
As outlined in the ARIA specification and corresponding Best Practices document, providing keyboard access requires, in part, that each widget has one tab stop by default and is responsible for discreetly managing focus for its descendants. Following these guidelines enables users to quickly navigate a page or application by using the tab key to move between widgets. Once a user has tabbed into a widget, they can then use other keys (the arrow keys for example) to move focus amongst the widget’s descendants.
Two Approaches
When it comes to managing focus, the WAI-ARIA Best Practices document provides two different techniques for developers: the Roaming TabIndex Technique and use of the activedescendant property.
Using the Roaming TabIndex Technique
The Roaming TabIndex Technique requires each of a widget’s descendants be focusable, either through the use of natively focusable HTML elements, or by making an element focusable using the tabIndex attribute. To use this technique, begin by setting the tabIndex attribute of a widget’s first descendant to a value that is equal to or greater than 0. (A value of 0 will result in the tab order of the widget being relative to its position in the page. Use a value greater than 0 to precisely control a widget’s tab order.) Next, set the tabIndex attribute of all remaining descendants to -1. (A value of -1 removes an element from the default tab flow, while preserving its ability to be focused via JavaScript.) This ensures that all of a widget’s descendants are focusable via JavaScript, but only one is in the default tab flow of its containing page or application, and therefore focusable by the user.
With these tabIndex values, use a keydown event handler to manage focus of the descendants once the widget is focused by the user. As the user presses the arrow keys, call the focus method to activate the appropriate descendant and update the tabIndex of the remaining descendants so that the currently focused element is the only one that is natively focusable.
The following menu button example illustrates how to use the Roaming TabIndex Technique to create a widget that is both keyboard and screen-reader accessible. To test this example yourself, you can use the free NVDA Screen Reader and Firefox 3. Alternatively, you can watch the screen cast of the example running in Firefox 3 using the NVDA screen reader.
Roaming TabIndex Example
Test Menu Roaming TabIndex Example
Roaming TabIndex Example Screen Cast
Menu Button Using Roaming TabIndex Technique @ Yahoo! Video
The Roaming TabIndex Technique Best Practices
Having studied the WAI-ARIA Best Practices document, as well as having used the Roaming TabIndex Technique in several widget implementations, I have distilled several best practices for using this approach:
- I prefer using natively focusable elements instead of using the
tabIndexattribute to make non-focusable HTML elements focusable, for better backward compatibility in browsers that don’t support thetabIndexattribute on all elements. - Use the
keydownevent when binding handlers used to manage focus since it is not possible to handle non-alphanumeric keys using thekeypressevent in IE. - In most cases it is necessary to prevent the browser’s default behavior when handling key events.
- When setting the
tabIndexattribute, avoid using thesetAttributemethod, to prevent case-sensitivity mistakes in IE. Setting thetabIndexattribute using the camel-case DOM property is both the most compact and most compatible syntax across browsers. For example:myElement.tabIndex = -1; - When updating the
tabIndexattribute of a widget’s descendants, set the attribute’s value to 0 before calling thefocusmethod to ensure that the element’s default focus outline is rendered in IE. - When styling a descendant’s focused state, work with or augment the browser’s default rendering of focus rather than suppress it. The default rendering of focus is familiar to the user and, in many cases, consistent with the browser’s host OS. Working with the default focus model improves the learnability of the widget. If you suppress the browser’s default rendering of focus, be sure to provide a focus model that is consistent across your entire site or application so that the user only has to recognize and learn one focus model within a single context.
- Set focus to HTML elements using both the
setTimeoutmethod and atry/catchblock. UsingsetTimeoutcan help screen readers keep up while the focus is being changed. I have found this to be true when testing on VoiceOver for the Mac. Atry/catchblock can help suppress unwanted XUL-related errors logged to the console when focusing elements in Firefox.
Using the activedescendant Property
Unlike the Roaming TabIndex Technique, use of the activedescendant property doesn’t require any of a widget’s descendants to be focusable. Instead, this technique requires only that the widget’s root element be made focusable via the tabIndex attribute. (Note: this technique doesn’t work in the current version of Safari as it doesn’t support the tabIndex attribute on all HTML elements.) Using this approach, the activedescendant property is applied to the widget’s root element, and as the user presses the arrow keys, the value of the property is set to the id of the element that represents the user’s current selection. Since this approach doesn’t rely on focusing a widget’s descendants via the focus method, the browser will not provide any default rendering of the user’s current selection. Therefore, when using the activedescendant property the developer is responsible for rendering focus for the widget’s currently active descendant via CSS.
activedescendant Example
The following example adapts the previous example to illustrate how to use the activedescendant property.
activedescendant Example Screen Cast
Menu Button Using The "activedescendant" Property @ Yahoo! Video
As illustrated in the screen cast, the activedescendant property can provide a user experience that is identical to the Roaming TabIndex technique.
Best Practices for Using the activedescendant Property
- Depending on the browser and the attribute’s value, setting the
tabIndexattribute on a widget’s root element can result in a focus outline being drawn around the widget. For widgets with descendants, having a focus outline surround an entire control is both unfamiliar to the user (not something you’ll see on the desktop), as well as ugly. So when using theactivedescendantproperty, it is best to suppress the focus outline. This can be accomplished by setting theoutlineCSS property in Firefox and IE 8, and using thehideFocusattribute for IE 6 and 7. Unfortunately it is not possible to suppress the focus outline in the current version of Opera. - Use CSS to render focus for a widget’s descendants in a way that is consistent with, and/or builds on, the default browser focus, or is consistent within the scope of the site or application.
Choosing a Technique
Having evaluated both the Roaming TabIndex Technique and the use of the activedescendant property, the Roaming TabIndex Technique is the better choice, because it is a solution that works “with the grain”. As such, it is more forward and backward compatible — especially when you are trying to support a wide array of browsers like we are at Yahoo!. Using the activedescendant property requires more effort for less overall benefit and compatibility. Here are the downsides to using the activedescendant property:
- Requires browser support of the
tabIndexattribute on all elements. Currently this not supported in Safari. - Suppressing the default focus outline drawn around a widget’s containing element is a slight pain in that it requires different techniques for different browsers. It turns into a bigger pain in Opera, where it is not only currently impossible but also exacerbated by Opera’s egregious focus model, illustrated in the following screen capture:

- Loss of the default, familiar focus outline drawn around a widget’s descendants. The focus outline can be restored via CSS. However, developers get the focus outline for free when using the Roaming TabIndex Technique.
- Since descendants aren’t focusable they cannot be clicked by pressing the enter key or space bar. This requires that developers listen explicitly for these key events and route the code responsible for handling the
clickevent accordingly. When using the Roaming TabIndex technique, developers can simply listen for theclickevent. - Every descendant needs a unique id.
Unlike the activedescendant property, the Roaming TabIndex Technique allows widgets to be both keyboard accessible and screen-reader accessible in browsers that don’t support ARIA and don’t support the tabIndex attribute on all elements. For example, if a widget’s descendants are built using the set of natively focusable HTML elements, users of screen readers will still perceive them as actionable/clickable elements. Consider the following screen cast of our first example running in IE 7 (a browser without ARIA support) using JAWS 10.
Screen reader accessible Menu Button @ Yahoo! Video
In this example, while the user doesn’t perceive the button’s menu as a menu, the screen reader does announce each button in the menu as it is focused — letting the user know that each item is actionable/clickable. Additionally, since the button’s menu is built using the natively focusable <button> element, this widget will be keyboard accessible to all A-Grade browsers, not just those that support the tabIndex attribute on all elements.
I suspect that the activedescendant property was developed as an alternative to the Roaming TabIndex Technique in part because the focus and blur events don’t bubble like other DOM events. This was a problem since developers need to listen for these events in order to customize how focus is drawn in a way that works cross browser, and attaching individual focus and blur event handlers to each of a widget’s focusable descendants has consequences for performance — especially for large composite widgets like trees and menus. That said, since we now have an easy way of listening for focus and blur in a performance-conscious way, I feel like there are currently more downsides than upsides to using the activedescendant property.
Share and extend: Bookmark with Yahoo! My Web | Bookmark with del.icio.us | digg it! | reddit!
7 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a comment

Copyright © 2006-2010 Yahoo! Inc. All rights reserved. Privacy Policy - Terms of Service
Powered by WordPress on Yahoo! Web Hosting.

It’s funny, I posted working library as a suggestion for YUI3 three days ago – http://yuilibrary.com/projects/yui3/ticket/2526008
http://code.google.com/p/qfocuser/ – standalone class for keyboard navigable AJAX widgets
Comment by Daniel Steigerwald — February 24, 2009 #
Yep, I strongly recommend roaming tabindex too. Nice post.
Comment by David Bolter — July 7, 2009 #
This article was very helpful. I have one point of general confusion. Clearly being keyboard accessible is good for both non mouse users and sight impaired users. The examples often point to having a one tab stop widget and then using arrow keys. However my testing so far with JAWS 10 shows that the browser never receives the arrow keys because JAWS treats them as special reading keys. So now my widget is no longer keyboard accessible.
Anyone have thoughts on this catch-22?
Comment by John Snyders — August 7, 2009 #
Hi John -
You are correct by default the virtual buffer is enabled in JAWS, meaning that the arrow keys are intercepted by the screen reader. This is the case for all screen readers. However, in the more recent versions of ARIA-enabled screen readers, the screen reader will automatically toggle the virtual buffer off by default when focus is given to an element with an ARIA role applied. And the last time I checked this was the behavior for JAWS 10 as well. If you are finding that not to be the case, perhaps you have your installation of JAWS configured differently.
- Todd
Comment by Todd Kloots — August 10, 2009 #
@Todd: actually, the behavior you are describing comes from NVDA, http://www.nvda-project.org, and not JAWS, http://www.freedomscientific.com, screen reader. At least I do not remember seeing JAWS toggle virtual buffer off when an ARIA-enabled widget receives focus. NVDA, however, does so for sure.
@David: the only way to force a screen reader to toggle virtual buffer is to place your widget inside a role of application. This is what we have done inside the “search assist” widget of the Yahoo! Search, http://www.ysearch.com.
Comment by Victor Tsaran — August 10, 2009 #
[...] some great examples of how widgets should react to keyboard use, and Todd Kloots of Yahoo does a great job of explaining the techniques behind good keyboard usability (also as a video and using YUI3 and focusing on WAI-ARIA). Patrick Lauke of Opera also wrote a [...]
Pingback by Find The Right JavaScript Solution With A 7-Step Test « Designers' Digest — January 28, 2010 #
[...] Improving Accessibility Through Focus Management [...]
Pingback by Some links for light reading (24/2/09) « Max Design — January 29, 2010 #