Accessible Interdependent Selectboxes

In the constant struggle to make web sites accessible to everyone, we sometimes have to reconsider some of the techniques we use in web development.

One of the main obstacles is to "de-script" forms. For years we have been spicing up forms with Javascript, and, if we didn't consider the consequences, didn't know better, or weren't allowed to elaborate due to tight deadlines, we made forms dependent on Javascript.

The classic interdependent select box

The classic example is interdependent select boxes. These are two or more select boxes, that allow the user to choose an option of one, and the content of the second gets automatically updated depending on the choice. A very neat way to filter search options or available options. Airlines use them a lot, as most flights from one airport go to a defined number of other airports.

Classic example Accessible example

  

  

  

  

  

The technique behind is to manipulate the options array of the select boxes, something that can only be done "on the fly" with Javascript.

Script, begone!

To offer a similar functionality, but make it independent of scripting, we have several options. One would be to shift all the logic to the backend, and reload the page every time you select an option of the first box. This'll be the safest way to do it, but it means another step for the user.

A nice way to work around is to rethink the concept of the interdependent select box, and make it work with normal form functionality:

Instead of using two select boxes and changing their options via Javascript we replace the first one with a row of radio buttons. Each radio button has a select box connected to it.

This is not really a 100% replacement, as the benefit of a select box - the same screen space for loads of options - is not given anymore, but it's a feasable option.

Via Javascript, we hide all the select boxes and only show the one connected to the radio button, once the radio button is selected.

Users without Javascript, or older browser that are not able to understand DOM, display all the select boxes.

HTML

<form id="mainform">
<p><input type="radio" onfocus="hide(0)" name="choice" value="one" id="choice1" />
<label for="choice1">Choice1</label>
<span>
<label for="select1">Options 1</label> 
<select name="select1" id="select1">
	<option value="s1_1">s1_1</option>
	[...]
</select>
</span></p>
<p><input type="radio" onfocus="hide(1)" name="choice" value="two" id="choice2" />
<label for="choice2">Choice2</label>
<span>
 <label for="select2">Options 2</label> 
<select name="select2" id="select2">
	<option value="s2_1">s2_1</option>
	[...]
</select>
</span></p>
<input type="submit" value="Send" />
</form>

As the Javascript uses DOM to find the SPAN to hide and the P to highlight, all we need to do to add another select is to add it after the last one:

<p><input type="radio" onfocus="hide(2)" name="choice" value="three" id="choice3" />
<label for="choice3">Choice3</label>
<span>
 <label for="select3">Options 3</label> 
<select name="select3" id="select3">
	<option value="s3_1">s3_1</option>
	[...]
</select>
</span></p>

Notice we need to increment the counter for hide().

To hide all select boxes, we call the hide() function with an id of "none".

<body onload="hide('none')">

Javascript

function hide(id){
	if (document.getElementById && document.createTextNode){
		spans=document.getElementById('mainform').getElementsByTagName('span');
		m=document.getElementById('mainform');
		for (i=0;i<spans.length;i++){
			m.getElementsByTagName('span')[i].style.visibility='hidden';
			m.getElementsByTagName('p')[i].style.background='#eee';
			m.getElementsByTagName('p')[i].style.borderColor='#ccc';
		}
		if(id!='none'){			
			m.getElementsByTagName('span')[id].style.visibility='visible';
			m.getElementsByTagName('p')[id].style.background='#ffc';
			m.getElementsByTagName('p')[id].style.borderColor='#000';
		}
	}
}

The background and bordercolour change is just there to add some eye candy.

If there is more than one instance on the page, we need to turn 'mainform' into a second variable added to hide().

Any other way?

Another solution would be to turn all the option of the first select into headlines with radio buttons for the dependent select boxes and hide and show the radio groups with DOM. How to show and hide them was explained in the Collapsible page elements with DOM article.

To see the code here in action, go to the Demo page.