Usable multiple-selection with checkbox lists and jQuery

There are two out-of-the-box methods for multiple selection in HTML: checkboxes and the <select> tag. Neither are perfect – I’ll be discussing why, and proposing a sort of mashup of the best aspects of both, using jQuery.

The vanilla HTML implementations of these two methods are shown below:

1) Select tag:

(Hold ctrl or command to select multiple values)

2) Checkboxes and Label tag:

Note that the <label> tag allows users to click the label to toggle the checkbox on and off.

In terms of usability,  the checkbox method is more straightforward – it is obvious how to select multiple values, whereas with the select method we have to tell the user which keys to hold down. In addition to that, if a user has selected multiple items, and then forgets to hold the correct key on the next click, their selection is lost and only the last value clicked is selected. On a list that can be scrolled, it may not even be apparent that the other selections have been lost.

The disadvantages of the checkbox method are:

  • It’s not obvious that the label can be clicked.
  • It would be nice if a larger area were clickable, as with the SELECT example
  • It would be nice if the entire row were highlighted, as with the SELECT example
  • The values are not scrollable – adding more will simply show a longer list

We’re going to fix all that with some simple CSS and Javascript (using JQuery).

Click to see an example page

Edit 1 – 9/4/09: Simplify code as per Victor’s comments, and fix refresh issue in Firefox

Edit 2 – 9/4/09: Simplified again, using just the label tags, without <a> tags, from the reddit comments



	$(document).ready(function() {

		// make sure labels are drawn in the correct state

		$('label').each(function()
		{

			if ($(this).find(':checkbox').attr('checked'))
				$(this).addClass('selected');

		});

		// toggle label css when checkbox is clicked

		$(':checkbox').click(function(e)
		{

			var checked = $(this).attr('checked');
			$(this).closest('label').toggleClass('selected', checked);

		});

	});

7 thoughts on “Usable multiple-selection with checkbox lists and jQuery

  1. Viktor

    Hi!

    if (checked)
    {
    $link.addClass(‘selected’);
    $checkbox.attr(‘checked’, true);
    } else {
    $link.removeClass(‘selected’);
    $checkbox.attr(‘checked’, false);
    }

    ==

    $link.toggleClass(‘selected’);
    $checkbox.attr(‘checked’, !($checkbox.attr(‘checked’)));

    ?

    Reply
  2. admin Post author

    Hi Victor, thanks for the comment.

    The problem with the code you posted is two-fold: it assumes the link already has the correct class for its state, and it flips the checkbox state based on the current state.

    The problem with the first is that a lot of browsers try to maintain the state of the form on refresh. This means that if you tick some boxes and then refresh, the selected items would be ticked, but not have the correct class. With your code, if you then clicked, it would toggle to the wrong class again. The solution to this would be to make sure the items have the correct class when the page loads – I’ll look into adding that.

    The problem with the second is that we deal with two different events – clicking the link and clicking the checkbox itself. When you click the checkbox, it changes state automatically before this code gets run. Therefore if you simply toggle the state, it will toggle back to its original state. If you try using preventDefault(), the checkbox will still change state before the code is run, the code will toggle it off again, and then the preventDefault() runs, also turning it off (preventing the default behaviour) so it doesn’t help. This is why I treat the link and the checkbox event separately and pass the desired state to applyChecked().

    If we implement the class checking on page load as I mentioned earlier, then the following code should work:

    $link.toggleClass(’selected’);
    $checkbox.attr(’checked’, checked);

    Reply
  3. Remi Roques

    For IE6/7, try that CSS: got rid of the 26px, padding and the posititon attributes.

    body {
    padding: 40px;
    font-family: Arial, Helvetica, sans-serif;
    }

    h1 {
    font-size: 1em;
    }

    ul#albums {
    width: 220px;
    height: 160px;
    overflow-y: auto;
    overflow-x: hidden;
    list-style: none;
    padding: 0;
    border: 1px solid #CCC;
    }

    #albums li label {
    display: block;
    border-bottom: 1px solid #DDD;
    padding: 4px 4px 4px 4px;
    color: #000;
    outline: none;
    }

    #albums li label:hover {
    color: #000;
    background-color: #EEE;
    }

    #albums li label.selected {
    color: #FFF;
    background-color: #CCC;
    }

    #albums li label .checkbox {
    top: 2px;
    left: 2px;
    }

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>