Saturday, January 23, 2016

Native HTML5 Ternary Checkbox - With Labels!

I worked through creating a html ternary checkbox (a checkbox with a tertiary option) this morning - with labels! Woohoo!

Now that we can create a third option we need to tell the user what it means, so we probably need labels.

Here are some images of the results on-screen:





Given a checkbox like this:

<input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />

We can use the default 'Yes', 'No', 'All' options with this HTML:

<input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />
<span class="ternaryLabelsYesNoAll"></span>


OR, use custom labels:

Show Archived: <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />
<span class="ternary-option checked">Active Only</span>
<span class="ternary-option unchecked">Archived Only</span>
<span class="ternary-option alternate">All Records</span>


We add this JS to attach the handler and the function to run the ternary checkbox:

$(document).ready(function(){
    $(":checkbox.ternaryCheckbox").on("click",ternaryCheckbox);
});

function ternaryCheckbox(e){
    var $t = $(this),
        that = this,
        originalVal = $t.val(),
        checkedVal = originalVal,
        alternateVal = ($t.data("ternary") != undefined ? $t.data("ternary") : 2);
    // This should only be undefined the first time to cache the original value
    if ($t.data("primary") == undefined) {
        $t.data("primary",checkedVal);
    } else {
        checkedVal = $t.data("primary");
    }
    // if 'un-checking', and NOT in tern state, go to tern state, else normal checked or unchecked
    if($t.prop("checked")==false && $t.prop("indeterminate")==false && originalVal!=alternateVal) {
        $t.val(alternateVal);
        $t.prop("checked",true);
        $t.prop("indeterminate",true);
    } else {
        $t.val(checkedVal);
        $t.prop("indeterminate",false);
    }
};


Here is the Raw CSS:

.ternaryCheckbox ~ .ternaryLabelsYesNoAll {
    display: inline-block;
    font-weight: 100;
    margin-right: 21px;
    position: relative;
    width: 1px;
}
.ternaryCheckbox ~ .ternaryLabelsYesNoAll:after {
    content: "No";
    display: inline-block;
}
.ternaryCheckbox:checked ~ .ternaryLabelsYesNoAll:after {
    content: "Yes";
}
.ternaryCheckbox:indeterminate ~ .ternaryLabelsYesNoAll:after {
    content: "All";
}

.ternaryCheckbox ~ .ternary-option {
    display: inline-block;
    font-weight: 100;
    min-width: 22px;
}
.ternaryCheckbox ~ .ternary-option.alternate, .ternaryCheckbox ~ .ternary-option.checked {
    display: none;
}
.ternaryCheckbox:checked ~ .ternary-option.checked {
    display: inline-block;
}
.ternaryCheckbox:indeterminate ~ .ternary-option.checked, .ternaryCheckbox:checked ~ .ternary-option.alternate, .ternaryCheckbox:checked ~ .ternary-option.unchecked {
    display: none;
}
.ternaryCheckbox:indeterminate ~ .ternary-option.alternate {
    display: inline-block;
}



Here is the Sass CSS:

/* Ternary Checkbox and Option Labels */

/* Using default 'No', 'Yes', 'All' default labels:
    <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1"<? if (local.example != 0)> checked</?><? if (local.example == 2)> indeterminate</?> />
    <span class="ternaryLabelsYesNoAll"></span>
    // Nothing else is needed, CSS does the rest.
*/
.ternaryCheckbox {
    ~ .ternaryLabelsYesNoAll {
        display: inline-block;
        font-weight: 100;
        margin-right: 21px;
        position: relative;
        width: 1px;
        &:after {
            content: 'No';
            display: inline-block;
        }
    }
    &:checked  {
        ~ .ternaryLabelsYesNoAll:after {
            content: 'Yes';
        }
    }
    &:indeterminate ~ .ternaryLabelsYesNoAll:after {
        content: 'All';
    }
}


/* Using custom ternary labels:
    <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1"<? if (local.example != 0)> checked</?><? if (local.example == 2)> indeterminate</?> />
    <span class="ternary-option checked">Checked</span>
    <span class="ternary-option unchecked">Unchecked</span>
    <span class="ternary-option alternate">Alternate</span>
*/
.ternaryCheckbox {
    ~ .ternary-option {
        display: inline-block;
        font-weight: 100;
        min-width: 22px;  /* Override this if longer values are being used, inline style is fine */
        &.checked,
        &.alternate {
            display: none;
        }
    }
    &:checked {
        ~ .ternary-option.checked {
            display: inline-block;
        }
        ~ .ternary-option {
            &.unchecked,
            &.alternate {
                display: none;
            }
        }
        &:indeterminate ~ .ternary-option {
            &.checked {
                display: none;
            }
            &.alternate {
                display: inline-block;
            }
        }
    }
}

-GBuilt

[This solution is completely open source, absolutly free to use without any restriction. Please give creative to this blog post URL.

No comments: