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

<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>

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 didnt 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


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&rsquot; 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.