Using WAI-ARIA Roles and States with the YUI Menu Control

By YUI TeamDecember 21st, 2007
Victor Tsaran (left) and Todd Kloots of Yahoo! Image of Victor Tsaran by Stephen Woods; image of Todd Kloots by Sandy Leung. Used by kind permission.

About the Authors: A new YUI example demonstrates how to use the WAI-ARIA Roles and States with YUI’s Menu Control. In this article, YUI Menu author Todd Kloots and Yahoo! accessibility guru Victor Tsaran introduce the WAI-ARIA Roles and States, explain how they dovetail with Menu, and provide a detailed account of the user experience with two different screen readers.

What are WAI-ARIA Roles and States?

Developed by IBM, and adopted by the W3C, the WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) Roles and States provide a means of making DHTML widgets and content accessible to assistive technologies such as screen readers. Much as CSS can be used to completely change the visual presentation of an HTML element, the WAI-ARIA Roles and States can be used to transform how HTML elements are presented to users of assistive technologies.

How it works

Implemented as a set of HTML attributes, the WAI-ARIA Roles and States bridge the gap between DHTML and assistive technology. For example: while CSS provides a means of painting a <ul> element as a menu, and JavaScript allows for the implementation of the expected menu-like behaviors for that <ul> element, a screen reader only communicates to the user that the menu is a <ul> element. Therefore, there is a gap between the developer’s intention for the role an HTML element is to play as a DHTML widget and how that widget is presented to a user of assistive technology. The WAI-ARIA Roles and States close this gap, allowing the developer to accurately communicate the role an HTML element is to play in the scope of a DHTML widget. When an element has WAI-ARIA Roles and States applied, a screen reader will announce its role and current state when it is focused. This allows <ul> elements to be presented as menus, <div> elements to be presented as modal dialogs, etc.

The value of a DHTML Library

The application of the WAI-ARIA Roles and States alone does not make a widget accessible. It it is still up to the developer to implement the mouse and keyboard functionality that the user expects for the role applied to a given widget. For this reason, a DHTML widget library can be helpful in that the nitty gritty of implementing the correct keyboard and mouse behaviors is done for you. Such is the case with the YUI Menu library. The YUI Menu implements all of the expected menu-like keyboard and mouse behaviors, so all the developer needs to do is apply the WAI-ARIA Roles and States.

Applying Roles and States to a YUI Menu

The WAI-ARIA Roles and States can be applied to a YUI Menu instance regardless of wether it is built using existing markup on the page, or entirely through JavaScript. However, since the WAI-ARIA Roles and States depend on Menu’s JavaScript-based keyboard functionality, it follows that the attributes representing the WAI-ARIA Roles and States only be applied via JavaScript. This progressive enhancement strategy ensures the best possible user experience by only applying WAI-ARIA Roles and States when the browser technologies required to support them (in this case, CSS and JavaScript) are available.

When applying the attributes representing the WAI-ARIA Roles and States to a Menu widget, it is best to do so via a “render” event listener. Waiting for a Menu’s “render” event to fire ensures that all of its DOM elements have been appended to the document and are available to be scripted. Roles and states are added to a Menu’s DOM elements via the setAttribute method and removed via the removeAttribue method. The following excerpt from the the Menu example demonstrates this technique.

/*
  Add the WAI-ARIA Roles and States to the MenuBar's DOM elements once it 
  is rendered.
*/

oMenuBar.subscribe("render", function () {

  /*
     Apply the "role" attribute of "menu" or "menubar" depending on the type of 
     the Menu control being rendered.
  */

  this.element.setAttribute("role", 
          (this instanceof YAHOO.widget.MenuBar ? "menubar" : "menu"));


  /*
     Apply the appropriate "role" and "aria-[state]" attributes to the label of
     each MenuItem instance.
  */

  var aMenuItems = this.getItems(),
    i = aMenuItems.length - 1,
    oMenuItem,
    oMenuItemLabel;
  

  do {

    oMenuItem = aMenuItems[i];


    /*
      Retrieve a reference to the anchor element that serves as the label for 
      each MenuItem.
    */

    oMenuItemLabel = oMenuItem.element.firstChild;


    // Set the "role" attribute of the label to "menuitem"

    oMenuItemLabel.setAttribute("role", "menuitem");


    // Remove the label from the browser's default tab order

    oMenuItemLabel.setAttribute("tabindex", -1);


    /*
      Optional: JAWS announces the value of each anchor element's "href"
      attribute when it recieves focus.  If the MenuItem instance's "url" 
      attribute is set to the default, remove the attribute so that JAWS 
      does announce its value.
    */

    if (oMenuItem.cfg.getProperty("url") == "#") {

      oMenuItemLabel.removeAttribute("href");
    
    }


    /*
      If the MenuItem has a submenu, set the "aria-haspopup" attribute to 
      true so that the screen reader can announce 
    */

    if (oMenuItem.cfg.getProperty("submenu")) {
    
      oMenuItemLabel.setAttribute("aria-haspopup", true);
    
    }

  }
  while (i--);
  

  /*
     Set the "tabindex" of the first MenuItem's label to 0 so the user can 
     easily tab into and out of the control.
  */

  if (this.getRoot() == this) {
  
    this.getItem(0).element.firstChild.setAttribute("tabindex", 0);
  
  }

});

The tables below lists the complete set of the menu-specific WAI-ARIA Roles and States and how they map to YUI Menu DOM elements.

Related ARIA Roles

WAI-ARIA Role YUI Menu DOM Element
menu <div class="yuimenu">
menubar <div class="yuimenubar">
menuitem <a class="yuimenuitemlabel"> and <a class="yuimenubaritemlabel">
menuitemcheckbox <a class="yuimenuitemlabel">
menuitemradio <a class="yuimenuitemlabel">

Related ARIA States

WAI-ARIA State YUI Menu DOM Element
haspopup <a class="yuimenuitemlabel"> and <a class="yuimenubaritemlabel">
checked <a class="yuimenuitemlabel">
selected <a class="yuimenuitemlabel"> and <a class="yuimenubaritemlabel">
disabled <a class="yuimenuitemlabel"> and <a class="yuimenubaritemlabel">

Once the WAI-ARIA Roles and States are applied, there are a few tweaks that can be made to the YUI Menu’s DOM elements to further improve the user experience. For YUI Menu, the label of each MenuItem instance is represented in HTML as an anchor element (i.e. <a class="yuimenuitemlabel">), and in IE and Firefox, anchor elements are automatically part of the tab order. Having MenuItem labels in the tab order by default is important when JavaScript is disabled to ensure that the user can navigate a Menu via the keyboard with the tab key.

Since the YUI Menu code provides its own, desktop-like keyboard functionality when JavaScript is enabled, having every MenuItem label in the browser’s default tab order can be a nuisance to users screen readers. When navigating the document with the tab key, users of screen readers have to tab through every single MenuItem label in a Menu, regardless of whether or not they want to use the Menu control. This problem can be solved by setting the “tabindex” attribute of every MenuItem label but the first to a value of -1. Setting an element’s “tabindex” attribute to a value of -1 removes it from the browser’s default tab order, while maintaining its focusability via JavaScript. Since the YUI Menu keyboard functionality is activated when any MenuItem label has focus, with just one MenuItem label in the browser’s default tab order the Menu’s keyboard functionality will be preserved, while at the same time giving the user the ability to quickly tab into and out of the control.

Supported Browsers and Screen Readers

In order to take advantage of the WAI-ARIA Roles and States a user must have both a web browser and screen reader that support them. Firefox 1.5 was the first browser to support the WAI-ARIA Roles and States, and its implementation has evolved considerably in version 3, making it much easier for developers to apply the attributes representing roles and states. Both Microsoft and Opera are planing to implement the WAI-ARIA Roles and States in future versions of their browsers. The two major screen readers, Freedom Scientific’s JAWS and GW Micro’s Window-Eyes both support the WAI-ARIA Roles and States, JAWS as of version 7.1 and Window-Eyes as of version 5.5. Regardless of the screen reader you choose, it is necessary to turn off the virtual buffer in order to take advantage of the WAI-ARIA Roles and States.

Known Issues

The YUI Menu example that uses the WAI-ARIA Roles and States was tested using Firefox 3 beta along with JAWS 8 and 9, and Window-Eyes 6.1. The user experience with JAWS and Window-Eyes was almost identical, but there were a few small differences worth mentioning.

JAWS

Each MenuItem in a YUI Menu has a url property that can be used to specify a URL that it will automatically navigate to when clicked. Setting the “url” property, sets the “href” attribute of the anchor element that serves as the MenuItem’s label. If no value is specified for a MenuItem’s “url” property, the “href” attribute of the anchor element is set to “#” by default. When a role of “menuitem” is applied to a MenuItem’s anchor element, JAWS still reads the value of the “href” attribute, which can be undesirable if the value of the “href” is set to “#.” In such cases, it is best to just remove the “href” attribute.

One of the cool feature of JAWS is that when navigating a page’s DOM using the virtual buffer mode, if an element is selected that has one of the WAI-ARIA Roles applied, JAWS will automatically switch off the virtual buffer to take advantage of the WAI-ARIA Roles and States.

Window-Eyes 6.1

When the first item in a MenuBar receives focus, Window-Eyes doesn’t announce the role of “menubar,” but rather just the text label of the item along with its state.

YUI Menu and the disabled WAI-ARIA State

There is currently a minor issue with Menu and ARIA where the disabled state cannot be used with MenuItems. This is because if a MenuItem is disabled, Menu currently skips over it when navigating with the keyboard (a behavior based on menus in OS X). This keyboard behavior will be updated in a future release of YUI Menu so that disabled MenuItem instances can be properly communicated to assistive technology.

Resources

9 Comments

  1. could you please apply these principles of equal access to the yahoo account creation interface? currently, it is necessary to pass a visual turing test in order to create an account, which means that those who cannot process the visual challange, cannot join the community… why isn’t there an aural alternative to the visual-only “challange”? what steps is yahoo taking to ensure that its backplane is enhanced by the work of yahoo employees in the field of accessibility?

    i applaud the addition of WAI-ARIA to the YUI Menu Control, but my applause is tempered by the fact that one cannot fully participate in these fora unless one can visually process an image…

  2. Great example of ARIA implementation.

    I have some troubles to use it with keyboard only because you remove the menu from the tab order. Some people use the keyboard to navigate without a screen reader and for them I didn’t found a way to use the menu.

  3. Gregory,
    Thank you for your comment. This has been discussed on our corporate blog at http://yodel.yahoo.com. Short answer: alternative is in the works.

    Goetsu,
    Thank you for staying on topic. You can effectively use the menu widget even if you do not use screen reader. The desktop-like keyboard navigation applies to this menu as well, i.e. use arrow keys to traverse, ESCAPE to exit out of menus.

  4. Kevin Decker said:
    March 25, 2008 at 7:44 am

    Thank you for the article.

    Hopefully this is not too off topic, but it seemed applicable.

    I just wanted to let the community know about a particular nasty bug that I experienced while using the YUI menu with the above ARIA attributes. Our code was calling menu.render with the appendToNode parameter defined every time the content of the menu changed (Which is admittedly a poor practice).

    On the second call to render, JAWS would read “Context Menu, Use up or down keys to navigate” and exit out of Virtual Cursor mode, in favor of PC Cursor mode. After this occurred, JAWS would not return to virtual cursor mode, regardless page reloads, Ins+Z toggling, etc. The only way that I was able to restore virtual cursor mode was to restart the Firefox instance.

  5. Thank you for the article.
    I think your article help so many users with their WAI-ARIA and before I have some troubles to use it with keyboard only because you remove the menu from the tab order.
    Your article is very usable for me. Thank you. :)

  6. I believe the separator role was missed out in the example.

    Using a stand-alone element (may be a hr) as a separator and adding role=separator to might be a way to achieve it

  7. [...] Finally, Todd Kloots from the YUI team presented the progressive enhancement features of the YUI Menu Control which he’s blogged about here previously. [...]

  8. [...] Yahoo! User Interface: Although this blog is not dedicated juyst to accessibility issues, this particular post covers WAI-ARIA; and a search (in the widget provided) returned 11 pages of posts related to accessibility.  Mostly very educational. [...]