Chris Hoffman’s
Outstanding Elephant

jARIA jQuery Plugin

jARIA is a plugin for the jQuery javascript library that adds ARIA support to Web applications. It is based on a javascript library written for Mozilla by IBM.

About ARIA

Modern Web application programmers comonly eschew built-in custom HTML controls, such as text inputs and radio buttons, in favor of custom-built widgets such as tabs and sliders. Because these custom widgets are not standardized, there is no way for screenreaders or other assistive technologies to interpret their functions or values.

The W3C’s ARIA working draft attempts to address this issue by specifying a set of roles for custom HTML widgets, states that widgets with given roles can have, and methods for assigning given roles to given widgets.

The jARIA plugin

The jARIA plugin adds the following methods to the jQuery object:

ariaRole()
Returns the ARIA role of the first matched element.
ariaRole(role)
Assigns the ARIA role role to each of the matched elements.
ariaRoleFilter(role)
Returns the set of elements that have the given ARIA role.
ariaState(state)
Returns the value of the given ARIA state for the first matched element.
ariaState(state, value)
Sets the ARIA state state on each matched element to value.
ariaState(obj)
Sets the ARIA states and values in obj to each of the matched elements, where obj’s keys are state names and its values are state values.
ariaStateFilter(state, value)
Returns the set of elements that have an ARIA state with the given values.
ariaParse()
Applies roles and state infoprmation found in the class attributes of the matched elements and their descendants. Triggers the ariaready event on the selected elements when the information has been parsed.

The following custom event is defined:

ariaready
Fired on the document object when the document has been parsed for ARIA information.

As well as the following selectors:

:ariaRole(role)
Selects all elements that have an ARIA role set to role.
:ariaState(state=value)
Selects all elements that have their ARIA state state set to value.
:ariaState(state)
Selects all elements that have their ARIA state state set to “true”.

Examples

Example #1

Let’s start with a jQuery-UI slider:

Here's the HTML:

<div id="firstSlider" class="ui-slider-1">
<div class="ui-slider-handle"></div>
</div>

Example #2

Now let’s add roles and states to the slider. We could add them programmatically with ARIARole() and ARIAState(), but this time we’ll add them using the class attribute of the slider div.

<div id="secondSlider" class="ui-slider-1 axs slider valuemin-0 valuemax-100 valuenow-0">
<div class="ui-slider-handle"></div>
</div>

The “axs” in the class attribute is a placeholder that separates the regular class information from ARIA-related class information. The first classname following the “axs” is assigned as the element’s ARIA role, and the subsequent classnames are assigned as ARIA states. Hyphens (-) separate state names and values, so, for example, “valuemax-100” assigns the value 100 to the element’s valuemax state. If no value is supplied, the default is the string “true”.

The next step is to make our javascript match up with our ARIA states. We can do all the work in the slider() method:

$(document).bind("ariaready", function(){

  /* Everything happens when the "ariaready" event is triggered. */
  
  $("#secondSlider").slider({
    minValue : $("#secondSlider").ariaState("valuemin"),
    maxValue : $("#secondSlider").ariaState("valuemax"),
  
  /* We set the initial slider values based on the ARIA states. */
  
    change : function(e, ui) {
  
  /* We use the change() method to change the ARIA valuenow state. */
  
      $(ui.slider.element).parent().ariaState("valuenow", ui.slider.curValue);
    }
  });
});

(A note on the rather convoluted syntax above: ui.slider.element is the slider handle. By wrapping it in a jQuery object we can easily access its parent element, which is the slider itself.)

Now whenever the slider is moved, the valuenow ARIA state gets updated. You can see the changes happen either by watching the HTML using the Firebug extension for Firefox, or by using the Firefox Accessibility Extension for the same browser (make sure you install at least version 1.3 alpha for ARIA compatibility).

Example #3

Now it’s time to kick it up a notch. Let’s use the slider to control the contents of a text box that can be submitted with a form.

The HTML:

<div id="thirdSlider" class="ui-slider-1 axs slider valuemin-0 valuemax-100 valuenow-0 controls-myFirstTextbox">
<div class="ui-slidvar element = $(e.target);  
  var controlee = $("#" + element.ariaState("controls"));er-handle"></div>
</div>

<input type="text" id="myTextbox" class="axs textbox controls-thirdSlider">

Notice that the we have set up a bidirectional relationship with the ARIA controls state: The slider controls the value of the textbox, and the textbox controls the value of the slider. Here’s the javascript for the slider:

$("#thirdSlider").slider({
  minValue : $("#thirdSlider").ariaState("valuemin"),
  maxValue : $("#thirdSlider").ariaState("valuemax"),
  change : function(e, ui) {
    $(ui.slider.element).parent().ariaState("valuenow", ui.slider.curValue);
    var controlee = $("#" + $(ui.slider.element).parent().ariaState("controls"));
    
    /* ariaState("controls") returns the value of the ARIA controls state for the slider,
       which is itself an id that we can use to access the controlled element. */
    
    controlee.val(ui.slider.curValue);
    
    /* Set the value of each controlled element to the value of the slider. */
  }
});

And here is the javascript for the textbox:

$("#myFirstTextbox").keyup(function(e){
  /* Gets called when a key has been pressed in the textbox. */
  
  var element = $(e.target);  
  var controlee = $("#" + element.ariaState("controls"));
  controlee.ariaState("valuenow", element.val());

  /* Set the contolee (i.e. the slider)’s valuenow ARIA state to the
     value of the textbox. */  
});

Example #4

The final step is to add some validation to the textbox. We’ll all another element and assign it the ARIA role of alert:

<span id="notification" class="axs alert"></span>

We need to add validation code to the keyup event for the textbox:

$("#mySecondTextbox").keyup(function(e){
  var element = $(e.target);  
  var controlee = $("#" + element.ariaState("controls"));
  controlee.ariaState("valuenow", element.val());

  var valuemin = parseInt(controlee.ariaState("valuemin"));
  var valuemax = parseInt(controlee.ariaState("valuemax"));
  
  /* Get the minimum and maximum values for the slider. */
  
  if (isNaN(element.val()) || element.val() < valuemin || element.val() > valuemax) {
    $("#notification").text("The value must be a number between " + valuemin + " and " + 
      valuemax + ", inclusive.");
    
  /* Put an error message in the notification area. */
    
    element.ariaState("invalid", "true");
    controlee.ariaState("invalid", "true");
    
  /* Set the ARIA invalid states of both the slider and the textbox to "true". */

  } else {
    $("#notification").empty();
    
  /* Clear the notification area. */
    
    element.ariaState("invalid", "false");
    controlee.ariaState("invalid", "false");
    
  /* Set the invalid state of both the slider and the textbox to "false". */
  }
});

Moving the slider guarantees that the textbox value will be valid, so we can get the textbox to validate itself by firing its onkeyup event from the slider’s slide function:

$("#fourthSlider").slider({
  minValue : $("#fourthSlider").ariaState("valuemin"),
  maxValue : $("#fourthSlider").ariaState("valuemax"),
  change : function(e, ui) {
    $(ui.slider.element).parent().ariaState({valuenow : ui.slider.curValue, disabled : "false"});
    
    /* Set both the ARIA valuenow and disabled states. */
    
    var controlee = $("#" + $(ui.slider.element).parent().ariaState("controls"));
    controlee.val(ui.slider.curValue);
    controlee.keyup();
    
    /* Fire the onkeyup event on the textbox. */ 
  }
});

To do

  • Another facet of ARIA is keyboard accessibility. You’ll notice that each of the sliders on this page is tab-accessible. You should also be able to change it with the arrow keys and Home and End. The most recent version of jQuery-UI includes keyboard-accessible sliders, at least with the arrow keys. Indeed, accessibility is a stated priority for the jQuery-UI team.
  • It would be nice to set the initial slider (or other UI component) values based on the ARIA states, but both the slider initialization and the ARIA initialization happen in $(document).ready(). Maybe I could create and fire an “onariaeady” event when the ARIA has been parsed? Done!