This proposal is intended address the problem of device-, OS-, and localization-independent control of widgets in accessible rich internet applications. The authors of this document do not believe the existence of this problem should block adoption of WAI-ARIA 1.0. The PFWG ISSUE-352, initially raised in August 2009, has been deferred to consideration for ARIA 2.0.
The authors anticipate that this proposal will not be published as a standalone W3C Recommendation. Instead, the authors request that the features proposed in this document be integrated, as appropriate, into the specifications for HTML 5, DOM Level 3, and/or ARIA 2.
At the time of this writing, the current draft of WAI-ARIA states that:
Accessibility of web content requires semantic information about widgets, structures, and behaviors, in order to allow assistive technologies to convey appropriate information to persons with disabilities. [The WAI-ARIA] specification provides an ontology of roles, states, and properties that define accessible user interface elements and can be used to improve the accessibility and interoperability of web content and applications. These semantics are designed to allow an author to properly convey user interface behaviors and structural information to assistive technologies in document-level markup.
The WAI-ARIA 1.0 draft specifies an adequate and standardized means for web applications to convey accessibility semantics through declarative markup in the DOM. However, there is currently no standardized, robust means for assistive technology to assume control of customized user interface widgets, or convey the user's intent for control of the web application. Simple control over web applications can be achieved by using standard activation events, like click
or DOMActivate
, but full control over secondary actions (tree expansion, grid sorting, scrolling) can only be achieved by using a set of keyboard shortcuts promoted by a group outside the W3C WAI calling itself the DHTML Style Guide Working Group. The style guide recommends authors register for all key events and listen, for example, for Control+Shift+M to open a popup menu during a drag and drop operation.
While we appreciate the efforts of the DHTML Style Guide Working Group, we feel that user interface should be controlled by operating systems, and not defined as part of any technical specification. We also believe that there are many serious problems with the DHTML Style Guide, including the following items:
For these reasons and others, we believe adoption of complex behavior in ARIA 1.0 widgets will be slow for any control that cannot be activated with a single, easy-to-learn, easy-to-remember, localization-independent keystroke like arrow keys, PageUp, PageDown, Home, End, Spacebar, Enter, Delete, Escape, etc. We also believe that the keyboard shortcuts recommended in the DHTML Style Guide should only be used as a temporary stop-gap measure. The authors wish to encourage the HTML, DOM, and PF Working Groups to provide a standardized solution with the utmost expedience.
It is in this interest that we offer the following proposal, which we believe solves the aforementioned problems. The proposal is organized into three parts: UI Change Request Events for all user agents, Accessibility Events for assistive technology, and additions to the Navigator interface for Assistive Technology Identification and Notification.
The core principle behind UI Change Request Events is that they operate on a completely backwards-compatible, opt-in basis. In other words, the web application author has to be aware of these events and register event listeners, or the user agent and assistive technology behave as they normally would.
Unlike other proposals that allow user agents or assistive technology to make direct changes to the DOM, these change request events do not cause any direct manipulation or mutation of the DOM. Instead, the event object conveys the user's intent to the web application, and allows the web application to make the appropriate changes to the DOM, on behalf of the user agent or assistive technology. If a web application is authored to understand the change request event, it can cancel the event using preventDefault()
, which informs the user agent or assistive technology that the event has been captured and understood. If a web application does not cancel any change request event, the event returns to the user agent or assistive technology, which can then attempt fallback behavior or communicate to the user that the input has not been recognized.
Note: The UIRequestEvent interface does not inherit from AccessibilityEvent (proposed in the following section), because we believe it will ultimately be useful outside the context of assistive technology. The DOM Working Group may find this a lightweight, performant alternative to certain mutation events. For example, DOMAttrChangeRequest
instead of DOMAttrModified
.
interface UIRequestEvent : UIEvent {
// UA or AT notifies web app of a change request
const unsigned short UNDO = 1;
const unsigned short REDO = 2;
const unsigned short CANCEL = 3;
const unsigned short DELETE = 4;
// expect more type constants will be added for other event types…
// ZOOM_IN / ZOOM_OUT ? perhaps that should just be slider widget, covered under ValueChangeRequest
readonly attribute unsigned short eventType;
void initUIRequestEvent(
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in views::AbstractView viewArg,
in long detailArg,
in unsigned short eventTypeArg
);
};
UndoRequest
Initiated when the user agent or assistive technology sends an 'undo' request to the web application.
eventType
RedoRequest
Initiated when the user agent or assistive technology sends a 'redo' request to the web application.
eventType
EscapeRequest
Initiated when the user agent or assistive technology sends a 'escape' request to the web application.
eventType
DeleteRequest
Initiated when the user agent or assistive technology sends a 'delete' request to the web application.
eventType
UndoRequest
event. Web authors who have registered for this event should process the event to determine whether to cancel the event. If the 'undo' action is understood in the context of the web application, web authors should undo the user's change, and cancel the event using the event object's preventDefault()
method. If the event is not cancelled by the web author, user agents may pass the literal interaction event to the web application; for example, as a keypress event.EscapeRequest
event. Web authors who have registered for this event should process the event to determine whether to cancel the event. If the 'escape' action is understood in the context of the web application, web authors should perform the appropriate action (such as closing the dialog), and cancel the event using the event object's preventDefault()
method. If the event is not cancelled by the web author, user agents may pass the literal interaction event to the web application; for example, as a keypress event.An area where this proposal is notably lacking is in regards to the precedence of event order in mainstream user agents, especially in regards to continuous input events. For example, user interactions with starting and ending events (touchstart/touchend, shakestart/shakeend, etc.) should probably take precendence over UIRequestEvents in mainstream user agents. UIRequestEvents are only intended to be used in mainstream user agents where appropriate, but the definition of "where appropriate" is not something we would attempt to define at the time of this proposal. Instead, we offer the previous examples for the sake of discussion.
interface UIScrollRequestEvent : UIRequestEvent {
// for custom scroll views or widgets (e.g. carousels, lists, grids)
const unsigned short LEFT = 1;
const unsigned short UP = 2;
const unsigned short RIGHT = 3;
const unsigned short DOWN = 4;
const unsigned short LEFT_LIMIT = 5;
const unsigned short TOP_LIMIT = 6;
const unsigned short RIGHT_LIMIT = 7;
const unsigned short BOTTOM_LIMIT = 8;
readonly attribute unsigned short scrollType;
void initUIScrollRequestEvent(
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in views::AbstractView viewArg,
in long detailArg,
in unsigned short eventTypeArg
in unsigned short scrollTypeArg
);
};
ScrollRequest
Initiated when the user agent or assistive technology sends a scroll request to the web application. Scroll events need only be used on custom scroll views (lists and grids showing data subsets, carousels, etc.), as user agents and assistive technologies already manage scrolling of native scroll views.
Note: The scroll type constants are more or less equivalent to expected behavior for PageUp/PageDown and Home/End keys on native scroll views, but also allow horizontal scrolling.
scrollType
interface UIValueChangeRequestEvent : UIRequestEvent {
// value changes (e.g. ranges)
const unsigned short INCREMENT = 1;
const unsigned short INCREMENT_SMALL = 2;
const unsigned short INCREMENT_LARGE = 3;
const unsigned short INCREMENT_MAX = 4;
const unsigned short DECREMENT = 5;
const unsigned short DECREMENT_SMALL = 6;
const unsigned short DECREMENT_LARGE = 7;
const unsigned short DECREMENT_MIN = 8;
readonly attribute unsigned short changeType;
void initUIValueChangeRequestEvent(
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in views::AbstractView viewArg,
in long detailArg,
in unsigned short eventTypeArg,
in unsigned short changeTypeArg
);
};
ValueChangeRequest
Initiated when the user agent or assistive technology sends a value change request to the web application.
Web authors should code applications to accept all values of the changeType
argument. For example, if there is no special behavior for INCREMENT_SMALL
or INCREMENT_LARGE
, web applications would behave as if they had received a basic INCREMENT
change type.
eventType
Users, wanting to change the value of a custom range widget (slider, media progressbar, etc.) in a web application, can indicate their intent a number of ways, including pressing various keys (Up, Down, Left, Right, PageUp, PageDown, Home, End) on most keyboard-controlled interfaces, and through gestures on many touch-enabled interfaces. User agents understanding this intent should initiate a ValueChangeRequest
event. Web authors who have registered for this event, should process the event to determine whether to cancel the event. If the value change action is understood in the context of the web application, web authors should change the value of the associated widget by an amount determined via the changeType
argument, and cancel the event using the event object's preventDefault()
method. If the event is not cancelled by the web author, user agents may pass the literal interaction event to the web application; in this case, in the form of a keypress or touch event.
interface DOMAttributeChangeRequestEvent : UIRequestEvent {
readonly attribute DOMString attrName;
readonly attribute DOMString newValue;
void initDOMAttributeChangeRequestEvent(
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in views::AbstractView viewArg,
in long detailArg,
in unsigned short eventTypeArg,
in DOMString attrNameArg,
in DOMString newValueArg
);
};
DOMAttrChangeRequest
Initiated when the user agent or assistive technology sends an attribute change request to the web application. In order for web applications to understand the intent of change request events from the user agent or assistive technology, these change requests should be limited to attributes for which a change in value indicates a discrete, defined action for known types of widgets and UI elements.
Note: Currently, this limitation indicates that DOMAttrChangeRequest
only applies to WAI-ARIA widgets, but it has the potential to be used with future iterations of HTML5 or SVG.
attrName
, newValue
DOMAttrChangeRequest
event on the tree item element, with the attrName
equal to aria-expanded
, and the newValue
equal to true
or false
.DOMAttrChangeRequest
event on the column header element, with the attrName
equal to aria-sort
, and the newValue
equal to ascending
or descending
.The following events are only initiated by assistive technologies, as opposed to mainstream user agents.
interface AccessibilityEvent : UIEvent {
void initAccessibilityEvent(
in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in views::AbstractView viewArg,
in long detailArg
);
};
AXFocus
(Editorial Note: possibly renamed AXFocusIn
)Initiated when the assistive technology cursor moves to a particular DOM node.
AXBlur
(Editorial Note: possibly renamed AXFocusOut
)Initiated when the assistive technology cursor leaves a particular DOM node.
AXDragSelect
Initiated by the assistive technology in order to inform the web application than a draggable element (e.g. an element with an explicit aria-grabbed
value) should be marked for dragging.
AXDragCancel
Editorial Note: This event may not be necessary; could use general EscapeRequest instead.
Initiated by the assistive technology in order to inform the web application than the current drag operation should be cancelled.
AXDragDrop
Initiated by the assistive technology in order to inform the web application than a specific drop target (e.g. an element with an explicit aria-dropeffect
value) should receive the drop event of the current drag operation.
In certain cases, it is beneficial for web authors to be aware of the assistive technology in use. This section defines a collection of attributes that can be used to determine, from script, the kind of assistive technology in use, in order to be aware of considerations for a particular assistive technology, including the need to support the UI Change Request Events or Accessibility Events defined in previous sections. Web authors should always limit client detection to detecting known versions. Web authors should always assume future versions and unknown versions to be fully compliant.
The accessibility
attribute of the Navigator interface must return an instance of the Accessibility interface, which represents the identity and state of the assistive technology, and allows web pages to optionally notify assistive technology of certain interface events that cannot be indicated through declarative markup such as WAI-ARIA roles, states, and properties.
interface Accessibility {
readonly attribute InterfaceObject accessibility; // Editorial Note: Is it necessary to define this attribute in the IDL?
// objects implementing the Accessibility interface also implement the ScreenReader and AccessibilityNotifications interfaces
};
Accessibility implements AccessibilityNotifications;
Accessibility implements ScreenReader;
Accessibility implements Magnifier;
Accessibility implements Speech;
[Supplemental, NoInterfaceObject]
interface AccessibilityNotifications {
void elementsChanged();
void screenChanged();
};
window.navigator.accessibility.elementsChanged()
window.navigator.accessibility.screenChanged()
The screenreader
attribute of the Accessibility interface must return an instance of the ScreenReader interface:
interface ScreenReader {
readonly attribute InterfaceObject screenreader; // Editorial Note: Is it necessary to define this attribute in the IDL?
// objects implementing the ScreenReader interface also implement the interfaces given below
};
ScreenReader implements ScreenReaderID;
ScreenReader implements ScreenReaderStatus;
[Supplemental, NoInterfaceObject]
interface ScreenReaderID {
readonly attribute DOMString name;
readonly attribute DOMString version;
};
[Supplemental, NoInterfaceObject]
interface ScreenReaderStatus {
readonly attribute boolean active;
};
window.navigator.accessibility.screenreader.active
true
if a screen reader is running, or false
otherwise. User agents may return false
if the user has chosen to disallow sharing this information with the requesting domain.window.navigator.accessibility.screenreader.name
Apple VoiceOver
". User agents may return an empty string if the user has chosen to disallow sharing this information with the requesting domain.window.navigator.accessibility.screenreader.version
4.0 (220.2)
". User agents may return an empty string if the user has chosen to disallow sharing this information with the requesting domain.Note: The authors recommend that user agents adopt a domain-level security policy for the ScreenReader interface that is similar to the security policy for location data or cookies. A user should be able to explicitly disallow sharing of this information altogether, or on a per-domain basis.
The magnifier
attribute of the Accessibility interface must return an instance of the Magnifier interface:
interface Magnifier {
readonly attribute InterfaceObject magnifier; // Editorial Note: Is it necessary to define this attribute in the IDL?
// objects implementing the Magnifier interface also implement the interfaces given below
};
Magnifier implements MagnifierID;
Magnifier implements MagnifierStatus;
Magnifier implements MagnifierNotifications;
[Supplemental, NoInterfaceObject]
interface MagnifierID {
readonly attribute DOMString name;
readonly attribute DOMString version;
};
[Supplemental, NoInterfaceObject]
interface MagnifierStatus {
readonly attribute boolean active;
};
[Supplemental, NoInterfaceObject]
interface MagnifierNotifications {
// Editorial Note: I'm not partial to the method name focusPosition. Any other suggestions?
void focusPosition(
in DOMElement element,
in optional array cursorRect,
in optional array selectionPolygon
);
};
window.navigator.accessibility.magnifier.active
true
if a screen magnifier is enabled (even if the current zoom level is 1.0), or false
if a magnifier is not enabled. User agents may return false
if the user has chosen to disallow sharing this information with the requesting domain.window.navigator.accessibility.magnifier.name
Apple Universal Access Zoom
". User agents may return an empty string if the user has chosen to disallow sharing this information with the requesting domain.window.navigator.accessibility.magnifier.version
4.0 (220.2)
". User agents may return an empty string if the user has chosen to disallow sharing this information with the requesting domain.window.navigator.accessibility.magnifier.focusPosition ( element, cursorRect, selectionPolygon )
Returns void. Allows the web author to send an explicit notification informing the screen magnifier to update its cache of the cursor location. Web authors should call this method when updating the display or cursor position of custom views.
DOMElement element
canvas
) that has focus.optional array cursorRect
[0,0]
position of focused element. [ x1, y1, x2, y2 ]
optional array selectionPolygon
[0,0]
position of focused element. [ x1, y1, x2, y2, ... xn, yn ]
Editorial Note: It may be better if the optional params are shape objects with a coords array and a type string like 'rect' or 'poly'. That would allow the author to decide if they wanted to provide the extra polygon coords, or just use a simple shape.
Note: The focusPosition()
method would be necessary for screen magnifiers to work with canvas-based web apps like Bespin or the 280 North projects. This method is not necessary for text views managed by the user agent, including contentEditable
views.
The speech
attribute of the Accessibility interface must return an instance of the Speech interface:
interface Speech {
// TBD, placeholder for speech-controlled user agents or assistive technology
// may need speech.synthesis and speech.recognition; each could have name/version/engine, etc.
// potential method: speech.synthesis.speak() to trigger TTS from web app
// potential method: speech.recognition.updateDictionary() to capture correct pronunciation of uncommon or app-specific words
};