There are currently some great examples of WAI-ARIA-enabled widgets out there making the rounds. In particular, there's Hans Hillen's JQuery Widget Samples and the collection from the OpenAjax Alliance.
These are nothing short of very useful. After all, ARIA is yet to be a full W3C recommendation (or standard, if you prefer), and we are all, or at least I am, still learning to write widgets with ARIA as best we can while assistive technologies continue to improve their support for it.
At the same time, I've noticed a few things about how some of these examples use the ARIA role="application"
attribute and value, and how certain screen readers deal with it, that I think are worth exploring.
In Which I Go on Yet Again About Tabs
I'm not sure what it is with me and tabbed interfaces. Perhaps, because of research I've done in the past, they are just something I feel comfortable and familiar with. In any case, when faced with a collection of sample ARIA widgets, I tend to gravitate to the tabbed interface examples first. I like to check out how they've been implemented and how they work with screen readers, usually JAWS and NVDA since these have the best support for ARIA right now.
Tabbed interfaces remain a common way to present web content, whether it's a series of form controls, images, or blocks of text; whether they are displayed horizontally or vertically; and whether they are presented as an accordion widget, or something like a sliding carousel or slideshow.
Are Tabbed Interfaces Applications?
This is the wrong question to ask. Instead, we should ask, "Is the content presented through the tabbed interface an application?" For instance, in the OpenAJax Alliance's tabs example, the content in the tab panels comprises a series of form controls for ordering a pizza, allowing you to specify the type of crust, toppings, and mode of delivery you desire. Except for the heading that appears in each panel, the content is nothing but interactive controls requiring input from the user. This is pretty obviously an application.
On the other hand, the tabs example on the JQuery Widget Samples page presents three tab panels that provide straightforward text content (including some links) describing dogs, cats, and sheep. Except for the minimal interactivity offered through the links contained in the text, the content is solely for reading. While one might consider the simple presence of tab controls to make this an application, I would suggest that because of what the tab panels contain, what we have here is not an application, but simply a particular presentation of regular text content that makes use of certain application-like, navigational controls. The user is not being asked to input any information to be processed, and the use of the tabbed interface is essentially presentational.
Why Does This Matter?
If it weren't for NVDA, I doubt that I would have as much to say about this. Allow me to explain; but first, a quick recap of virtual buffers and such.
Screen readers and Forms, or Focus, or Application Mode
When working with a web page, screen readers like JAWS and NVDA mostly read from a virtual buffer, what is effectively a snapshot of the DOM. Users can move through the virtual buffer of the page using special keyboard commands specific to the software. When in this virtual buffer mode, keyboard commands are intercepted by the screen reader and not passed through to the browser.
Since application widgets in the browser need to allow direct keyboard input from the user, screen readers also have a forms or focus mode. In the particular context of application widgets, we might also call it application mode. In this mode, keyboard commands are passed through to the browser and not intercepted by the screen reader. This allows the user to do things like type text into a form field, or change the currently active panel in a tabbed interface by using the arrow keys.
Tab Controls Initiate Application Mode by Default
When focus is set to a tab control, that is, an element that has an ARIA role
of tab
, both JAWS and NVDA automatically enter application mode, since the intended interaction for tab controls is to use the arrow keys to navigate among them. Once in application mode, moving focus, for example, by using the Tab key, from a tab control to a focussable element that does not require forms or focus mode, such as a link or checkbox, causes both screen readers to automatically exit focus mode. This occurs even if the focussable element is within the tab's associated content panel.
Additionally, if focus is currently set to a tab control, both JAWS and NVDA users can just as easily exit application mode manually with simple keyboard commands, and move on to navigating and reading the tab panel's content as they wish using the virtual buffer. So far, so good.
Adding role="application"
In the OpenAjax example, an ARIA attribute-value pair of role="application"
is set on a div
containing the tabbed interface elements, that is, the tab list, the tabs themselves, and their associated tab panels.
In the case of the JQuery Widget Samples page, all of the widget examples are collectively presented through a tabbed interface. A container div
with role="application"
wraps this overall collection of tab panels. Because the specific tabs widget example is contained in one these tab panels, it inherits the effects of role="application"
from the container div
. Additionally, the body
element on the page is also set with role="application"
.
Using role="application"
tells supporting assistive technologies to change their mode of behaviour. Instead of intercepting keyboard commands to allow interaction with the virtual buffer, they pass all keyboard input through to the browser as if dealing with an application. This goes for all of the content wrapped in a container with this role
, whether it's made of up explicit form controls or just simple text.
JAWS' Behaviour
Freedom Scientific has provided a Word document on how JAWS deals with ARIA, which has been kindly reproduced in HTML by the Paciello Group. In it one finds the following.
In HTML, when the ARIA role attribute on the BODY tag is set to “application”, JAWS will treat a Web page as though it were a traditional stand-alone application. This means that the virtual buffer JAWS typically uses to display Web pages will be turned off, and users will navigate using TAB and other such keystrokes which are normally provided in stand-alone apps to facilitate keyboard access…. And unlike forms mode, users cannot use the ESC key or the PC Cursor key to leave application mode when the role of “application” is placed on the “body” tag.
This is perhaps a little misleading, as it suggests, I think, that a JAWS user simply cannot exit application mode when role="application"
is applied to the body
tag. However, one can always press Insert+Z to toggle the virtual cursor, and thereby effectively leave application mode and start interacting with the widget's content through the virtual buffer and standard JAWS reading commands. This, I think, is very handy, especially where a widget contains content that is meant to be read, but it is quite different from the approach that NVDA takes, as we'll note shortly.
When focus is within an element with role="application"
that is a descendent of the body
element, JAWS users can still use Numpad+ to exit application or forms mode, and easily start reading the page's content. At the same time, in this scenario, JAWS will not automatically exit forms mode when focus is set to elements such as links or checkboxes as it normally would outside the context of role="application"
.
NVDA's Behaviour
For NVDA, when dealing with objects set with role="application"
, the virtual buffer just doesn't exist. Pressing Insert+Space to toggle virtual buffer or browse mode does nothing. Content inside an element with a role
of application
is just not rendered into a virtual buffer, and will never be available through NVDA's normal reading commands. Where such a widget's content is all application controls, as is the case with the OpenAjax tabs example, this is not a problem, as all of the content is natively focussable.
In the JQuery tabs example, on the other hand, where the tab panel content is a series of texts about dogs, cats, and sheep, this does present a problem. The only way for an NVDA user to read the tab panels' content is to use NVDA's object navigation commands, which allow the user to move from node to node through the DOM, reading each one as it goes. While this is an essential mode of navigation to provide, using it in this instance can make reading the text a rather disjointed affair.
For example, the text from the first sentence in the "Dogs" tab panel is The dog (Canis lupus familiaris,[1] is a domesticated form of the wolf, a member of the Canidae family of the order Carnivora.
This one sentence includes a good number of DOM nodes, including a
, b
, i
, span
, and sup
elements. Reading it by object navigation involves pressing the same key combination, Ins+Numpad6, a total of 14 times to move through ever node in the sentence: hardly a pleasant way to navigate or read text!
Whether pleasant or not, this behaviour is at least consistent with the way that James Teh, one of NVDA's lead developers, considers the question of role="application"
: ...an application should *never* be rendered into a virtual buffer. It's not just a question of browse and focus modes; an application is not supposed to engage the virtual buffer at all.
So What's the Gist?
Personally, I don't fully understand why NVDA so strictly keeps application content from being rendered in a virtual buffer, but I also don't understand much of the inner workings and programming of screen readers. While I certainly appreciate the benefit in JAWS allowing users to enter, albeit through more limited means, a virtual buffer even within an application, I'm happy to trust that NVDA's developers know what they are doing.
Certainly, in accordance with NVDA's behaviour, the result for developers is pretty obvious: Only use role="application"
for true applications comprising form and other interface elements that demand user input. Or, as James puts it, role=application
should not be used if the content could in any way be considered a 'document' which should be browsed.
But I think this holds even where JAWS' behaviour is concerned. It is clear from its more restricted approach to forms mode when role="application"
is applied to the body
or a descendent element that the same idea is at play, namely that applications are for interacting with directly through browser-level keyboard commands, and not through a virtual buffer.
Revisiting Our Examples
The OpenAjax Alliance Tabs Widget
As was noted at the beginning, the OpenAjax Alliance's tabs example can easily be considered an application. The content is really nothing but natively focussable form controls through which a user is meant to place their pizza order. With the slight exception of the heading text in each tab panel, there is no content that is meant to be browsed or read like a document. So role="application"
in this instance is perfectly fine.
As far as the heading text is concerned, it is not natively focussable, and will not be read by either JAWS or NVDA in application mode. Still, it is useful text to have since it adds context to the purpose of the list of controls in each panel. To make this text more readily available to screen reader users, it might be useful to give the heading an id
and reference it through an aria-labelledby
attribute on the ul
element wrapping the form controls. This would cause the screen reader, upon focus being set to the first item in the list of controls, to identify the list using the heading text. If we did this for the "Carnivore" tab panel, for example, NVDA would say "Carnivore property page, Select Carnivore Options, list, Pepperoni checkbox, not checked."
The JQuery Tabs Widget
For the JQuery tabs widget example, the tab panels' content is text about dogs, cats, and sheep that is meant to be browsed as a document: a screen reader user should be able to navigate and read the text through a virtual buffer's normal reading commands. As such, it should probably not use role="application"
. The tab controls themselves already initiate forms or application mode when receiving focus, so programmatically identifying the whole thing as an application is unnecessary in this regard. Doing so, however, does significantly reduce the ability of at least NVDA users, and to some degree also JAWS users, from accessing the panels' content.
I should clarify again that the individual JQuery tabs widget example is not explicitly wrapped in its own element set with role="application"
. It exists in its own tab panel as part of a larger set of tab panels wrapped by a div
set with a role
of application
. This amounts to the same thing, though, as far as screen reader behaviour goes, since the effects of role="application"
on the container div
are passed down to the element's children.
I would suggest that role="application"
should not be added to the div
wrapping the overall set of tab panels. In some cases, the sample widgets, notably the accordion, tabs, tooltip, and panel widgets, contain text content that should be browsable. Also, each sample widget appears in its own tab panel, and is accompanied by additional text identifying what accessibility changes have been made to the widget since its last incarnation. This additional text, and the text within those particular sample widgets just mentioned, will be difficult to access and read for NVDA and JAWS users.
For the same reasons, I would also say that role="application"
should not be set on the page's body
element either. Instead, role="application"
should probably only be applied to those specific widgets, e.g., the slider, menubar, checkbox, and tree, that are expressly application controls and that don't include any typically browsable or document-like content.
Conclusions
I've concentrated on two examples of tabbed interfaces that use role="application"
. However, the concerns that have been raised extend equally, I think, to all ARIA widgets where one might be apt to use role="application"
.
When building an ARIA widget, consider the widget's content and the type of interaction that users of screen readers and other assistive technologies will require. If the widget contains text for browsing, as opposed to text that is directly associated with a specific control or that labels a group of controls, just forego using role="application"
.
Only if the widget contains mainly application controls is role="application"
likely appropriate. And if it also contains some text that is meant to label or further describe those controls, consider using the aria-labelledby
and aria-describedby
attributes to associate that text as applicable.
Acknowledgements
I really have to thank Hans Hillen and the OpenAjax Alliance for creating and sharing their sample ARIA widgets. Despite my raising some issues with their implementations, without these examples there would be much less to work with as we try to figure all this stuff out. I'm grateful for the learning opportunity. I'm also thankful to James Teh for answering some of my questions about how NVDA works and interprets role="application"
.
role="application"