This is a fairly high level description of how to support device independent interaction. An understanding of general Dojo widget development and event handling within scripting and the Dojo Toolkit is assumed and not described.
Device Independent behavior means more than just supporting the keyboard. Where ever possible use the most generic event handler available. For example, consider a widget where the down arrow key selects an element in the widget. The selection needs to be distinguished with a specific style. Rather than modifying the style of the element when processing the down arrow key event, focus the item from the down arrow key event handler and change the style via a focus event handler. This way, if focus is set from a means other than the keyboard such as a voice input system, the styling is properly set and does not depend solely on keyboard actions.
Determining Key Behavior
When implementing keyboard navigation, the ideal solution is to mimic the behavior of the operating system. For example, the right and left arrow keys are used to expand and collapse nodes in a Windows tree control and the up and down arrow keys move between nodes in the control. Unfortunately it is not always possible to mimic the operating system or browser behavior because the widgets may not be able to capture the necessary keys. A group of industry representatives are working to create a style guide to describe the navigation and behaviors of Web widgets. When completed, this Style Guide will be provided to open source and Dojo plans to implement the recommendations. The Style Guide will attempt to normalize the differences between operating systems and provide a generalized solution for Web components
Within all widgets interaction with both the keyboard and the mouse is important. Users may switch between using the mouse and using the keyboard at any time. A widget author can not assume only keyboard or only mouse interaction. Thus, the widget component will generally need to store information about the current item with focus.
This can also be useful when the keyboard event handler is placed on an owning object in the component hierarchy rather than the actual element generating the event, for example on the table element rather than on each td element. Even though the event handler provides information on exactly what element generated the event, it is often necessary or easier to use the stored point of reference
In order to support both the mouse and the keyboard a component will usually have both onclick and onkey events. The onclick handler must include steps to update
the point of regard so that any keyboard actions after the onclick will continue to work. In
addition, the point of regard is often needed in order to update the style on
the element losing focus before updating the new item irregardless or whether
the mouse or the keyboard generated the event that results in a focus change.
Trapping Key Events
When implementing keyboard navigation, first determine where in the hierarchy to trap the key events. It is generally best to trap the key events at as high a level as possible and use the event object to determine that actual source of the event and perform the necessary action. This method prevents having to add a key handler to each individual element thus conserving the amount of markup to be generated. However, there may be cases where the event needs to be trapped at the level of each individual element. The actual source of the event is needed in order to determine how to process the keystroke received.
Once the component handles an event, it will usually stop that event from being propagated to other elements. For example, if the down arrow key is captured and moves focus to the next item in a tree control, the event should not propagate up to the browser where it might be interpreted as a command to scroll the page. Use the dojo.event.browser.stopEvent(event) method to stop the event.
In order to assist with key event handling, an onkey event has been added to Dojo to normalize key events. The appropriate key event, either onkeydown or onkeypress, will be used depending upon the browser. The key codes have been normalized as well. See dojo.event.browser class in dojo.event.browser.js.
Add the dojo onKey event into the widget template or via scripting using one of the dojo event connection apis.
Example using dojo.event.connect to connect the object represented by the node variable to the onKey handler function in the current object:
dojo.event.connect(node, "onkey", this, "onKey");
Example from tab container template to demonstrate adding the onkey handler and waiRole within the template:
<div id="${this.widgetId}" class="dojoTabContainer">
<div dojoAttachPoint="tablistNode"></div>
<div class="dojoTabPaneWrapper" dojoAttachPoint="containerNode"
dojoAttachEvent="onKey" waiRole="tabpanel"></div>
</div>
Tabindex and Focus
When navigating via the keyboard is it essential that the element that is navigated to receives focus. The focus should NOT be simulated via CSS - call the focus() method on the element. Styling can be used to enhance the visual focus or selection but should not replace actually setting focus on an element. A screen reader will only speak information about the element when it receives focus. Screen magnifiers rely on focus to move the zoomed viewport on the screen.
Use the tabindex value to provide direct or programmatic keyboard focus to an element. The tabindex attribute can be used to include additional elements in the tab order and to set programmatic focus to them.This was a feature implemented in Internet Explorer that has been extended to Firefox and Mozilla.The following table outlines the use of the tabindex attribute:
| Tabindex Attribute Value | Focusable via mouse or scripting via element.focus() | Tab Navigation |
| not present | Follow default behavior of element (only form controls and anchors receive focus) | Follows default behavior of element |
| zero - tabindex="0" | Yes | In tab order relative to element's position in document |
| positive - tabindex="x" (where x is a positive integer between 1 and 32768) | Yes | tabindex value directly specifies where this element is positioned in the tab order |
| negative - tabindex="-1" | Yes | Not in tab order, author must focus it with element.focus() as result of a key press. |
When adding support for keyboard navigation, consider the widget as a component. The tab key can be used to navigate from component to component on a page and then the arrow and other keys should be used to navigate within the component. Only one element in a given component should have a tabindex equal to zero at any one time. This allows the user to navigate into and set focus within in the component using the tab key. Then, trap the onkey events and use the arrow keys to navigate within the elements of the component. All of the elements within the component which can receive focus must have a tabindex equal to -1. When an element is programmatically given focus, its tabindex value is changed from -1 to 0 and the tabindex of the previous element with focus will be changed from 0 to -1. This will insure that only one element within the component is in the tab order of the page and that the element with tabindex = 0 is the most recently focused element in the component. For example, when creating a tree control, each tree item is represented by an element. The first tree item in the control will be given a tabindex of 0. All of the other elements which represent tree items and can receive focus programmatically will have a tabindex value of -1. An onkey handler will trap the keyboard events for the tree control. When a tree item element is given focus via element.focus(), the element’s tabindex will be changed from -1 to 0. and it will be put into the tab order. Now if the user moves focus out of the tree control (either via a mouse click or by tabbing to the next component on the page), when the user sets focus back into the tree control using the tab key, the last focused tree item, which was given a tabindex of 0, will receive focus.
The Accessible Rich Internet Applications Roadmap is being developed by the W3C Web Accessibility Initiative (WAI) Protocols and Formats working group. The group is creating specifications for role and state information which can be added to markup to provide semantic information about user interface components.The browsers will translate this role and state information into the accessibility api for the platform in use.Currently Firefox 1.5 and later supports this additional semantic information on the Windows platform where it converts the information into the Microsoft Active Accessibility (MSAA) api.When recent versions of the Window-Eyes and JAWS screen readers are used with Firefox, this additional information is spoken to the user.
Some HTML elements such as links and form elements have well defined roles and behaviors. Interactive controls created from generic elements can now also be identified with roles and states.When an element receives focus the role and state information provided by the developer will be made available to assistive technologies. For example, as a screen reader traverses through a Dojo Tree control using the arrow keys, as each tree item receives focus the title of the tree item will be spoken as well as its expanded or collapsed state if it has children. Likewise, a Dojo checkbox created using <div>and <pan> tags can be identified as a checkbox and its checked or unchecked state can be reported. When creating a new Dojo widget, the role of the widget must be identifed and the state of the widget must be set and updated as it changes.
As of January, 2007, the ARIA specifications are still under development; however a significant portion of the specification has been implemented in Firefox 1.5 and 2.0.
The public drafts of the specifications can be found at http://www.w3.org/wai/pf.
Accessible DHML in the Mozilla Developer Center provides additional information about using the ARIA specifications and includes a table of roles and states supported in current versions of Firefox.
Assigning Roles
Use the tabindex to provide keyboard focus or to allow programmatic focus to an object. By adding a tabindex to an element, the element will now be included in the accessibility hierarchy of the Firefox browser.Information about elements in the accessibility hierarchy will be provided to assistive technologies. If you use a tabindex attribute on a DIV, SPAN, IMG or any element which has no natural role of its own then you need to provide a role. Any element that can receive focus must have a role, either implied, such as input elements and anchors, or specified via a role attribute. For things with an implied role such as input fields and anchors, you can use tabindex=-1 to remove them from the tab order. You can also specify a different role for elements which already have an implied role.
The role and states are added to Dojo widgets within the widget template or via the dojo.widget.wai APIs as described in the Dojo Accessibility Strategy section.
Providing Hierarchical Information
In order for Firefox to determine the correct parent child relationships between objects, and to communicate this via an accessibility API to assistive technologies, it is best to create components in a hierarchical fashion. For example, when creating a menubar it is best to have the components that make up the menus and menuitems of the menubar be children of the menubar. Likewise, menuitems should be children of the owning menus. This hierarchy allows Firefox to provide menu information to the assistive technologies, and for a screen reader to speak more information about the menu such as, menu open, File, item 1 of X when the user opens a menu. Here is a simple pseudo code example demonstrating a hierarchical layout of elements for a menu control. This exmaple only shows the addition of role attributes and does not represent a complete menu widget.(Note: Attributes are not quoted in pseudo-code examples to help improve the readability):
<div role=menubar>
<div role=menuitem>A</div>
<div role=menu><divole=menuitem>A.1</div>
<div role=menuitem<A.2</div>
</div>
<div role=menuitem>B</div>
<div role=menu>
<div role=menuitem>B.2</div>
<div role=menuitem>B.2.1</div> </div>
</div>
It may not always be practical to create items via HTML in a hierarchical fashion. In that case the group role can help to associate the items properly. This is illustrated in the following simple pseudo code example of a tree hierarchy.
<div role=tree >
<div role=treeitem>Top>/div>
<div role=group>
<div role=treeitem>1>div>
<div role=group>
<div role=treeitem>1.1 </div>
<div role=treeitem<1.2>/div>
<div role=treeitem>1.3</div>
<div role=group>
<div role=treeitem>1.3.1<div>
<div role=treeitem>1.3.2>/div>
<div role=treeitem>1.3.3</div>
<div role=treeitem>1.3.4</div>
</div>
<div role=treeitem>1.4</div>
</div>
<div role=treeitem>2>/div>
<div role=treeitem>3</div>
<div role=group>
<div role=treeitem>3.1</div>
<div role=treeitem>3.2</div>
>/div>
</div>
</div>
The tree items at the same level in the hierarchy are grouped together within a DIV element identified with role=group. With this organization, the assistive technologies can be provided with the information about what level and item number a particular treeitem represents. For example, in the above tree example, with focus on item 1.3.3 a screen reader might speak, "one dot three dot three item three of four, level four" or something similar.
Other items included in the hierarchy may not be essential to the component. These items can be marked with a role of presentation to eliminate them from consideration when determining information about the component.
Using the Presentation Role
While it is preferable to use CSS for layout, tables are still used to quickly and easily arrange elements on a page. This is especially true of existing widgets which were originally created to work in older browsers. Putting information in tables can easily confuse the hierarchy of the component. If tables must be used, they can be marked with a role of presentation to eliminate them from the hierarchy. Here is a pseudo code example where the presentation role was used on tables within a tree component:
<div role=tree>
<table role=presentation>
<tr><td><div role=treeitem>Top</div>&;lt;/tdgt;</tr>
</table>
<div role=group>
<table role=presentation>
<tr><td><span role=treeitem>1</span></td></tr>
</table>
<div role=group>
<table role=presentation>
<tr><td><span role=treeitem>1.1</span&;gt;</td></tr>
</table>
<table role=presentation>
<tr><td><span role=treeitem>1.2</span></td></tr>
</table>
</div>
<table role=presentation>
<tr><td><span role=treeitem>2</span></td></tr>
</table>
</div>
</div>
Since the table is only used for layout it is identified with a role of presentation to remove if from the accessibility hierarchy so that information about the table is not provided to assistive technology.
Other elements may need to be removed from the accessibility hierarchy as well. For example, when creating a DHTML checkbox, an image may be contained within a span element that is marked with a role of checkbox and an appropriate state of checked equals true or false. The image which represents the checkbox is contained within the span and should not contain any alt text since the role and state are managed by the surrounding span. Images are considered important elements and are normally included with the accessibility hierarchy of the browser. In order to ignore this image in the accessibility hierarchy, it is marked with a role of presentation:

Assigning States
In addition to identifying the role of a widget, the state of the widget must be identified and updated. The initial state can be set within the widget template or via scripting when the widget is created. As the state changes during user interaction with the widget, the state must be updated using the dijit.util.wai apis:
dijit.util.wai.setAttr(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value) dijit.util.wai.getAttr(/*DomNode*/ node, /*String*/ ns, /*String|Boolean*/ attr) dijit.util.wai.removeAttr(/*DomNode*/ node, /*String*/ ns, /*String|Boolean*/ attr)
The ns value passed into these function is either "waiState" or "waiRole". The dijit.util.wai functions above are wrappers to the DOM apis to set, get and remove attributes. In browsers where namespaces are supported the setAttributeNS, getAttributeNS, and removeAttributeNS, apis are called. In other browsers the setAttribute, getAttribute and removeAttribute apis are called and the namespace is simulated. The namespace information is stored in the dijit.util.wai class.
It is important to update the state information as it changes so assistive technology users can be made aware of the change. For example, when a treeitem is expanded, the state for the element that has been assigned role=treeitem, must be set to expanded=true. Likewise, when a treeitem is collapsed, the state for the element with the role=treeitem must be updated to expanded=false. Be aware that some of the boolean states imply more than just a dual state. For the state attributes checked, selected and expanded a value of false indicates that the widget is capable of being checked, selected or expanded while no attribute indicates that the element is not capable of that state. For example, a tree node with children will have either a state of expanded=true or expanded=false depending upon whether the child nodes are visible or not. An end node, with no children will have no expanded state value set.
Generally only items which have a role can have a state value. The role may be explicitly set by the author such as a treeitem or may be implicitly defined such as a form element or link. Items which have been added into the accessibility hierarchy via a tabindex attribute may also have states such as desribedby or labelled by.
NOTE:As of February, 2007 the High contrast mode accessibility strategy has changed. Dojo will NOT be using background images to convey information. Since Dojo will use real img elements there is not a high contrast issue and separate a11y versions of the widgets will not be necessary. For now, when creating new widgets do NOT use CSS backgound images to convey information - use real img elements. This documentation will be updated when the strategy for creating multiple themes is in place. -Becky
All widgets must be visible and work when the operating system is set to high contrast mode. In this mode, colors and background images set via CSS are turned off. The CSS positioning attributes are still used but any color information is overridden by the colors selected for high contrast mode. The most common high contrast modes are black on white or white on black but any color combination can be set by the user. In addition to high contrast mode, the widgets should generally be usable with the display of images turned off in the browser. When images are turned off, the alt attribute for any images in the widget should provide the same information. There may be cases, such as an analog clock, where the alt attribute information can not substitute for the actual image. In these cases there should be an alternative method of obtaining the same information. In the case of an analog clock, a text display of the time would be appropriate, since it conveys that same information, the current time.
To avoid problems with high contrast mode it is best to create HTML widgets using the img element rather than relying on CSS background images. Since the use of img elements can have a negative affect on performance, many developers prefer to use background images even though they do not display in high contrast mode. In this case, an accessible version of the widget must be created that will work in high contrast mode.
The widget author must create an additional widget that derives from the original widget to support accessibility. This widget will be named with the a11y prefix. If the original widget name is dojo.widget.MyCoolWidget, the accessible version will be named, dojo.widget.a11y.MyCoolWidget. When using namespaces other than dojo, the same naming convention must be followed of appending a11y to the actual widget name. For example, the accessible version of mynamespace.MyCoolWidget becomes mynamespace.a11y.MyCoolWidget. The preferred location for this new class is within the same file as the original widget. This will make it easier to keep the two files in sync. Although, the reason for extending the original widget class to create the accessible version is to reduce the need to make changes in two places. The majority of the behavior and logic for the widget should remain in the original class. All of the keyboard support and role and state information belong in the original widget. The only modifications for the accessible version should be to support high contrast and images off mode.
The appropriate version of the widget will be loaded and used based on a check for accessibility that is performed in dojo.widget.buildWidgetFromParseTree():
// test for accessibility mode
dojo.a11y.setAccessibleMode();
If a check has not already been performed, dojo.a11y.setAccessibleMode will test to determine if high contrast mode is set or images are turned off in the browser. This test is only performed once and the results cached to improve performance. When images are turned off or high contrast mode is enabled, the dojo.a11y.accessible variable is set to true. In addition, the a11y prefix is added to the beginning of the dojo.render.html.prefixes array. This will cause dojo to load the a11y version of a widget if it exists rather than the default version. This is the same mechanism that is used to load an svg version of a widget if the browser supports svg and an svg version of the widget exists.
If the Dojo widget has an HTML equivalent, such button or checkbox, the accessible version can use the basic HTML type. This strategy will likely involving creating a new template for the accessible version of the widget. The new template name should include "a11" in the name to distinguish it from the standard template. For example the templates for the checkbox widget are named Checkbox.html and CheckboxA11y.html. The accessible version of the widget will refer to the accessible template via the templatePath variable.
If there is not an equivalent HTML element, the accessible version of the widget can replace the use of CSS background images with img elements. When using image elements the look and feel of the widget can not easily be changed since changes to the image source are likely to occur within the scripting code and can no longer be changed via style sheets. Since the purpose of the accessible widget is to support high contrast mode and high contrast mode does not support a color theme, the image set used is not critical. Certainly, there are some high contrast uses who may not be able to interpret the images due to the colors used within the images. But, there is no universal color scheme that can be used in the images that will suit all users. Users which can not interpret the images due to color or size will turn the images off and use the alt text. Thus, it is essential that alternative text is provided for all images using the alt attribute of the img elements.