Digital Web Magazine

The web professional's online magazine of choice.

Building Accessible Widgets for the Web

Got something to say?

Share your comments on this topic with other web professionals

In: Articles

By Mike West

Published on July 10, 2006

When building web applications, we’re working with a fairly restricted set of widgets, compared to those available for native desktop apps. The recent surge of interest in JavaScript points to a solution: We can replicate the functionality of sophisticated native widgets through some clever DOM scripting, and provide our users with exciting interfaces that bridge the gap between native apps and web apps.

This approach works wonders, and our interfaces can indeed be substantially improved through scripting. It’s critical, however, to ensure that we bring all our potential users with us as we work around HTML’s limitations. Building exciting interface behaviors is completely wrongheaded if doing so reduces accessibility. The interfaces we build ought to provide the same central functionality to all users, period.

Happily, there’s a straightforward way to ensure that a JavaScript-enhanced interface works correctly for even the least capable browser: build the interface in its most basic incarnation first. Before jumping ahead to the hi-fi widgets you’ve always dreamed of, think lo-fi. Dig into the core functionality you want to provide, and map it to the basic HTML elements you know you’ll always have available to you. You can keep your forms accessible—while significantly enhancing the experience for users of modern browsers—if you serve up a lo-fi form, and then unobtrusively transform it into an exciting hi-fi form "onload."

Think Lo-Fi First

A combo box is a great example of a native widget that we must build from scratch for the web. Let’s apply the lo-fi principle, and talk about how we might create a lo-fi combo box that provides the basic, no-frills functionality we’re looking for.

The central question is, “What does a combo box do?” At its core, a combo box is simply a drop-down list with the added ability to accept a user-entered value instead of the preset options. There are some other interesting UI bits like type-ahead search, but it’s really just a SELECT list with an INPUT text field glued on. If we want to provide users with the ability to pick values out of a list or enter their own free-form values, then we can implement the purely semantic meaning using those basic elements:

<fieldset class='combo_box'>
  <legend>Combo Box Widget</legend>
  <label for='select_value'>
    Select a value:
    <select name='select_value' id='select_value'>
      <option value=''></option>
      <option value='1'>lorem</option>
      <option value='2'>ipsum</option>
      <option value='3'>dolor</option>
      <option value='4'>sit</option>
      <option value='5'>amet</option>
    </select>
  </label>
  <label for='input_value'>
    Or, input your own:
    <input type='text' name='input_value' id='input_value' />
  </label>
</fieldset>

Simple, eh? We’ve grouped the INPUT and SELECT elements (and, of course, their LABELs) in a FIELDSET of class combo_box to signal their relationship to one another. This code distills the combo box down to its core components, and the result is basic enough that we know we’ve provided the desired functionality to anyone who uses the form. We can validate the input server-side if necessary, and create a seamlessly accessible interface for all users.

If we were creating a calendar control, we could start in exactly the same way. The core functionality of a calendar is the ability to pick an arbitrary day, month, and year. This maps cleanly to three SELECT elements, perhaps with the following structure:

<fieldset class='calendar'>
  <legend>Calendar Widget</legend>
  <label for='year'>
    Year:
    <select name='year' id='year'>
      <option value=''></option>
      <option value='1900'>1900</option>
      ...
      <option value='2006'>2006</option>
    </select>
  </label>
  <label for='month'>
    Month:
    <select name='month' id='month'>
      <option value=''></option>
      <option value='1'>01 – January</option>
      ...
      <option value='12'>12 – December</option>
    </select>
  </label>
  <label for='day'>
    Day:
    <select name='day' id='day'>
      <option value=''></option>
      <option value='1'>01</option>
      ...
      <option value='31'>31</option>
    </select>
  </label>
</fieldset>

The principle here is the same. We distill the core characteristics of the widget we’re creating, and then come up with a clean HTML isomorphism. With—and only with—that accessible foundation in place, we can start putting together the additional functionality for our hi-fi users.

Wireframe a Hi-Fi HTML Framework

JavaScript gives us the freedom to completely rework the DOM on the fly. This means that we needn’t feel at all limited by the lo-fi structure when creating our hi-fi interface. We can reshape the lo-fi HTML any way we wish in order to achieve the UI behavior that we’re looking for, so let’s continue with the combo box example by being specific about what that behavior is.

After playing around with the native combo box we’re trying to replicate, we might come up with this list of features:

We can divide this list fairly easily into behavioral and structural additions. We’ll set up various event handlers to handle the former (e.g. the Enter keystroke can be captured by hooking into an onkeyup event), and the latter will require modifications to our framework (e.g. we need a toggle button of some sort). These structural additions will be our first concern; event handlers aren’t much use without a solid structural framework to hang them on.

As it turns out, we can build the hi-fi combo box’s structure on the basic components of the lo-fi version (remember, it’s just a SELECT element and an INPUT element). The INPUT element is exactly what we need for the combo box’s text-entry field, and we can hide and show the SELECT element to replicate the combo box’s list of options. We’ll need to add a button of some sort (perhaps an INPUT of type image so that we can have a nice-looking arrow), and we should give the SELECT a size attribute so that multiple OPTIONs can be displayed at once, in keeping with the native widget’s appearance. The HTML code that reflects these changes might look something like this:

<fieldset class='combo_box'>
  <legend>Combo Box</legend>
  <label for='input_value'>
    <!-- The SELECT’s LABEL -->
    Select a value:

    <!-- The original INPUT -->
    <input type='text' name='input_value' id='input_value' />

    <!-- A new toggle button -->
    <input type='image' src='/path/to/image.png' />

    <!-- The original SELECT -->
    <select name='select_value' id='select_value' size='4'>
      <option value='1'>lorem</option>
      <option value='2'>ipsum</option>
      <option value='3'>dolor</option>
      <option value='4'>sit</option>
      <option value='5'>amet</option>
    </select>
  </label>
</fieldset>

With this new framework in mind, let’s discuss the behavioral modifications. The text-entry INPUT field needs a handler bound to the onkeyup event to enable the type-ahead search, the up and down arrow keys, and the enter/escape keys. The toggle INPUT button needs an onclick handler to support the hiding and showing of the SELECT list, and the SELECT needs an onclick handler to support the selection process we decided on.

See the demo for a working example. The technical details of ComboBox’s implementation are laid out in the comments of the ComboBox.js script, so those of you who are interested can dive right in. The remainder of this article will deal with the more general question of how that transformative code gets executed.

Transform Unobtrusively

We could certainly throw the relevant DOM manipulation into a SCRIPT block after each FIELDSET, but a cleaner and less obtrusive option exists. In the same way that external stylesheets provide the ability to strictly separate the semantic layer (HTML) from the presentational layer (CSS), we can separate the behavioral layer from everything else by creating a JavaScript object that runs when the page’s onload event triggers. We can throw the object’s definition and instantiation into an external file, meaning that a single SCRIPT tag at the top of our document can kick off the entire process.

The minimal frame for our object looks like this:

function ComboBox () {
  var self = this;
  self.instantiate = function () {
    // Interesting initialization code goes here
  }
  addEvent(window, 'load', self.instantiate);
}
var ComboBoxFactory = new ComboBox();

This code isn’t complex, but deserves careful attention. We’re creating a closure by defining a function named ComboBox, and setting up various methods and attributes inside.

The first line sets up self as an alias for this in order to avoid some scoping issues later on. Specifically, we’ll be able to set up event handlers inside our main closure that use the keyword this to refer to the event’s target (the INPUT or SELECT elements), and self to refer to the ComboBox object itself. For example, here’s the onclick handler for the SELECT element:

self.selectClickHandler = function(e) {
  /*
    If we click on the SELECT, set the INPUT to the text
    value of the selected OPTION, hide the SELECT, and
    focus on the input box.
  */
  var container = this.parentNode.parentNode;
  container.input.value = this.options[this.selectedIndex].text;
  this.style.display = 'none';
  container.input.focus();
  return false;
}

The event handler is triggered when the user clicks on the SELECT element, meaning that the function is bound to that element’s context. this, even in an event handler defined inside our closure, can be used to refer to the SELECT element without confusion if we consistently use self to refer to the closure itself.

The call to addEvent on the last line of the ComboBox function is critical, as it allows us to delay execution of the real innards of our object until the window’s onload event triggers. Let’s examine the step-by-step execution of the closure to make sure that everything’s clear:

  1. When the .js file is loaded, the closure is defined.

  2. The new operator on the last line of the file instantiates a new object, executing the code inside the closure.

    • self is created as an alias to this.

    • instantiate is created as a method of self, and assigned a function.

    • The addEvent call on the last line of the closure is executed, binding self.instantiate to the window’s onload event.

  3. The page finishes loading, and the onload event is triggered.

  4. The instantiate method of our ComboBox object is executed, transforming all the lo-fi combo boxes on the page into beautiful hi-fi versions.

This procedure makes JavaScript modifications as easy to implement as CSS. You can build a series of reusable, interface-enhancing JavaScript utilities, and reap the benefits with one simple SCRIPT tag to kick off the entire process. Combo boxes are just the tip of the iceberg.

Additional Reading

Got something to say?

Share your comments  with other professionals (0 comments)

Related Topics: Accessibility, Scripting, XHTML

 

Mike West abandoned suburban Texas' wide open plains in 2005 in favour of the Black Forest in Southern Germany where he currently lives and works. His musings about the web are periodically posted to his personal website, mikewest.org.

Media Temple

via Ad Packs