View Full Version : ARIA-enabled ComboBox

16 Jun 2009, 1:00 PM
I'm using Ext 2.2.1 and need an ARIA-enabled Ext.form.ComboBox. Where I primarily see the current ComboBox fall short of meeting the ARIA requirements is that it doesn't read the contents of the list items when using screen readers, such as JAWS. I am not an ARIA expert (been looking at it for about a day now), but I took a shot at enabling this. Let me know if you have any comments or better ideas on implementing this.

First, I started with the ARIA class that you can find in the Ext examples:

Ext.a11y.ARIA = Ext.apply(new Ext.util.Observable(), function() {
return {
setRole : function(el, role) {
el = Ext.getDom(el);
if(el) {
el.setAttribute('role', role.toString());

setProperty : function(el, key, value) {
el = Ext.getDom(el);
if(el) {
el.setAttribute(key.toString(), value.toString());

var ARIA = Ext.a11y.ARIA;

Then I augmented ComboBox as follows:

* Adds accessibility to the Ext.form.ComboBox by adding ARIA tags.
* The wrapper around the input field is used as the main 'combobox' widget.
* The following was copied from the "WAI-ARIA Best Practices" at:
* http://www.w3.org/TR/wai-aria-practices/#combobox
* The items in the list have been numbered by me and will be used in the code
* below to reference the item being addressed.
* ---- Copied from "WAI-ARIA Best Practices" -----------------
* A combo box is a combination of text field, which may be editable, a drop
* button to choose an item to place in the combo box, and a displayable list
* of items all wrapped in the form of a single widget. Like text fields a
* combobox should be labeled to determine the essence of the widget. Keyboard
* focus within the widget must be managed by the widget. Comboboxes are used
* extensively in graphical user interfaces and the design pattern for the widget
* should be semantically correct.
* 1. The container element that wraps the combobox must have a role
* of "combobox."
* 2. The first element within the combobox should be an input text field and
* is responsible for managing the keyboard focus between the textfield and
* the list as well as displaying the list. The textfield should be in the
* tab order. If create a textfield without using a standard HTML textfield
* form control then you must ensure that it is in the tab order.
* 3. If the textfield is not editable it must have have aria-readonly="true."
* 4. The next element should be an html <button> or another html element with
* a role of "button". This button should be in the tab order and be
* responsible for opening the list.
* 5. The next element constitute with a role="list" representing the drop down
* list and it should managed the keyboard navigation between each list item
* and back to the textfield if necessary.
* 6. Each item in the list should have a role="listitem". Listitems should not
* be in the tab order.
* 7. You should provide a label which labels the combobox by referencing the
* textfield in the combobox. You can use an aria-label to associate this
* label with the combobox or you may use the HTML <label> element and its
* for attribute to reference the textfield.
* ---- End copy ----------------------------------------------
* Note that item #7 is not being addressed at this time. In my implementation,
* the label was attached to the input field via a "for" on the label.
Ext.override(Ext.form.ComboBox, {

onRender: Ext.form.ComboBox.prototype.onRender.createSequence(function() {

// marks the input field as the combobox, see item #1 above
ARIA.setRole(this.wrap, 'combobox');

// adding 'textfield' is not technically necessary since "this.el" is an input
// field as described in item #2 above
ARIA.setRole(this.el, 'textfield');

// mark as readonly if not editable, see item #3 above
if (!this.editable)
ARIA.setProperty(this.el, 'aria-readonly', 'true');

// add role of 'button' to the trigger, see item #4 above.
// NOTE that I did not add the button to the tab order which is a violation of item #4.
// To do so would require additional coding to allow keyboard selection of the button.
ARIA.setProperty(this.trigger, 'role', 'button');
//ARIA.setProperty(this.trigger, 'tabIndex', '0'); // future?

// when the list is collapsed, clear aria-activedescendant so that the input field
// becomes the active element again
collapse:function() { ARIA.setProperty(this.el, 'aria-activedescendant', '');},

initList: Ext.form.ComboBox.prototype.initList.createSequence(function() {

// The drop down list is marked up the first time the list is activated
if (!this.ariaInit) {

// The 'innerList' is marked as an ARIA 'list' and the input field
// is marked as the owner of this list. See item #5 above.
ARIA.setProperty(this.innerList, 'role', 'list');

// Since the list is not a direct descendant of the combobox, the
// 'aria-owns' must be set.
ARIA.setProperty(this.el, 'aria-owns', this.innerList.id);

// Each element in the list is marked as an ARIA 'listitem'.
// See item #6 above.
ARIA.setProperty(el, 'role', 'listitem');

// When the user changes the selection, the selected object is identified
// as the active descendant for this ComboBox widget.
this.view.on('selectionchange', function(view,selectionsArray) {
if (selectionsArray&&selectionsArray.length>0) {
ARIA.setProperty(this.el, 'aria-activedescendant', Ext.get(selectionsArray[0]).id);
}, this);


I tested this using Firefox and JAWS 10 and pretty much got the behavior I was going for.

17 Jun 2009, 8:54 AM
Hi scottw,

That looks like a perfectly good solution to me. We are adding ARIA support to other components then just the Tree we did now. Thanks for the time you took to look into this.

1 Apr 2012, 11:35 AM
I tried using the above code for the combo box I am developing so that JAWS would be able to read it, but I am not able to make JAWS read it.

This is the combo box code I am using right now.
pg.qfld_award_type=new Ext.form.ComboBox({fieldLabel:'Award Type',lazyRender: true,name:'extAwardType',store:new Ext.data.SimpleStore({fields:['type','desc'],data:pg.AWARD_TYPES}),displayField:'desc',valueField:'type',typeAhead:false,mode:'local',triggerAction:'all',selectOnFocus:true,emptyText:'All',width:220,editable:false,xtype:'combo'})

Do you have any live examples using the above code/ similar code ?