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).
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);
});
});
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’)));
?
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);
Thanks for the reply!
I’m beginner in Web and JavaScript programming and tips
I have been looking for something along these lines for decades now! Thanks!
hi thanks for this it actually helped me out but wen i view in ie7 or ie6 it doesnt work why?
Hi there. Interesting UI. I join Eno: any idea for a fix for IE6/7 ?
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;
}