Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Tuesday, August 12, 2008

Multi-State Checkboxes

Recently, I was asked to build a 3-state system for checkboxes, so that there would be a checked, unchecked, and mixed state. So, I built a re-usabled widget that supports any number of states (not just the 3 mentioned above), and any number of checkboxes. I also desired that it be simple to use and easy to read.

The widget requires that you provide it a node in the DOM (preferably, an empty one) to contain the checkboxes, which it will clear and build your checkboxes inside. The DOM will be built as follows:

Example 1: Checkbox DOM

<ul> <li><label><input name="nameOfCheckbox1" type="checkbox" value="stateOfCheckbox1"/>Label for Checkbox 1</label></li> <li><label><input name="nameOfCheckbox2" type="checkbox" value="stateOfCheckbox2"/>Label for Checkbox 2</label></li> ... </ul>

We will be styling the checkboxes to be invisible (opacity = 0) and applying a ‘click’ event to each checkbox, which will be used to trigger the checkbox state change. The checkbox is wrapped in a label, so that supporting browsers will allow users to click on the label to fire the checkbox ‘click’ event as well. Also, by using an invisible checkbox we allow users to tab through the checkboxes and use space to trigger the ‘click’ event, not limiting users to mouse only interaction (this is why I didn’t use the traditional ‘hidden’ input to store state). Since the checkbox is invisible, we will need to use a background image attached to the label for our multi-state checkboxes. Here are the styles that I recommend:

Example 2: Checkbox Styles

.checkbox ul li { clear: both; list-style: none; } .checkbox ul li input { opacity: 0; filter: alpha(opacity=0); } .checkbox ul li label .checkbox ul li label.unchecked { background: transparent url(images/unchecked.png) 0px 2px no-repeat; } .checkbox ul li label.mixed { background: transparent url(images/mixed.png) 0px 2px no-repeat; } .checkbox ul li label.checked { background: transparent url(images/checked.png) 0px 2px no-repeat; }

Example 3: State Images

uncheckeduncheckedunchecked

For the most part the this widget was designed to just work. However, it requires that you provide a DOM node and a list of states you wish to setup. The state list specifies what classes should be applied to the label tag for each state, the value of the state, and what the next state will be when the user clicks on the checkbox. You may also pass an optional configuration parameter which may include: the initial data representing the checkboxes, whether you want to render the checkboxes immediately, and/or a function you would like to attach to the ‘onCheck’ event. Here is an example of how to initialize a checkbox widget:

Example 4: Initialize the Checkbox

Mint.Widget.Checkbox('checkbox', [ {klass: 'unchecked', next: 'B', state: 'R'}, {klass: 'mixed', next: 'B', state: 'G'}, {klass: 'checked', next: 'R', state: 'B'} ], { data: [ {name: 'tag-A', label: 'Tag A', value: 'R'}, {name: 'tag-B', label: 'Tag B', value: 'G'}, {name: 'tag-C', label: 'Tag C', value: 'B'}, {name: 'tag-D', label: 'Tag D', value: 'G'}, {name: 'tag-E', label: 'Tag E', value: 'R'} ], render: true });

If you do not provide a configuration parameter, you can call the public ‘render’ Function at any time to build the checkboxes. You may also call the ‘render’ Function with a new data set at any point in the future to redraw the checkboxes with new values. I have illustrated several different instantiations of this widget for your testing pleasure: Checkbox Widget.

posted by Matt Snider at 11:09 pm  

3 Comments »

  1. Hi Matt,

    when reading the title of this entry in my RSS reader, I was intrigued: nice concept - and a nice solution, too. I’m wondering why you chose an HTML checkbox instead of a radio input, as a checkbox is defined as an on/off switch whereas radio buttons do the job of handling multiple (mutually exclusive) states for one form variable. The script to hide the controls and define the order in which each value is checked would probably look similar, but you would gain a form that works just as well with JS turned off.

    Bernd

    Comment by Bernd Matzner — August 13, 2008 @ 1:00 am

  2. Really nice widget, I my self have make something similar for a recent project.

    Comment by Radoslav Stankov — August 13, 2008 @ 2:41 am

  3. Thanks for the feedback.

    Bernd, I choose a checkbox, because I was stuck in the mindset that I was building a checkbox widget. I believe you are correct that a similar, more accessible, script could be written using radio buttons. Such a solution would probably be HTML driven with the JavaScript hijacking the DOM and converting it to a multi-state checkbox. I’ll be looking into it when I have some time.

    Comment by Matt Snider — August 13, 2008 @ 8:47 am

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress