Indeterminate state demo

by Arif Hasan

HTML

<ul>
    <li><label><input type="checkbox" class="checkall" /> Check all</label>
        <ul>
            <li><label><input type="checkbox" class="child" /> Thing 1</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 2</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 3</label></li>
        </ul>
    </li>
    <li><label><input type="checkbox" class="checkall" /> Check all</label>
        <ul>
            <li><label><input type="checkbox" class="child" /> Thing 1</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 2</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 3</label></li>
        </ul>
    </li>
    <li><label><input type="checkbox" class="checkall" /> Check all</label>
        <ul>
            <li><label><input type="checkbox" class="child" /> Thing 1</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 2</label></li>
            <li><label><input type="checkbox" class="child" /> Thing 3</label></li>
        </ul>
    </li>
</ul>

CSS

ul {
    list-style: none;
}
label {
    display:block
}

label:first-child {
    font-weight:bold;
}

label:nth-child(n+2) {
    margin-left:1em;
}

JavaScript

var children = $('.checkall').closest('li').find('.child');

// catch changes to child checkboxes and fire .change() on load
$('.child').change(function(){
    // create var for parent .checkall
    var checkall = $(this).closest('ul').parent().find('.checkall');
        
    // do we have some checked? Some unchecked? Store as boolean varibles
    var someChecked = $(this).closest('ul').find(":checkbox:checked").length > 0;
    var someUnchecked = $(this).closest('ul').find(":checkbox:not(:checked)").length > 0;

    // if we have some checked and unchecked, set checkall to indeterminate. 
    // If all are checked, set checkall to checked

    checkall.prop("checked", someChecked || !someUnchecked);
        
// fire change() when this loads to ensure states are updated on page load
}).change();

// clicking checkall will check all children checkboxes under it
$('.checkall').click(function() {
    $(this).closest('li').find('.child').prop('checked', this.checked);    
});