Building Accessible Widgets for the Web

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:

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:

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:

A toggle button at the right edge of the text-entry INPUT field will show or hide the drop-down list when clicked.

Typing a value into the combo box’s text-entry field will show the drop-down list if it’s currently hidden, and the value that best matches that text will be highlighted.

Pressing the up or down arrow keys while focused on the text-entry field will move the selector up or down in the drop-down list, and will populate the text-entry field with the newly selected value.

Clicking on a value in the drop-down list will mark it as selected, populate the text-entry field with the newly selected value, and hide the drop-down list.

Pressing Enter or Esc will hide the drop-down list.

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:

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.

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:

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

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.

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

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

Ryan Campbell’s article Upgrade your SELECT Element to a Combo Box provided the initial inspiration for this article’s example code. I prefer my mechanism to his, simply because his doesn’t provide the same core functionality to users without JavaScript.

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.