Custom Checkbox

by Mike McCaughan

HTML

<div class="custom-checkbox">
  <div class="amcom-checkbox">
    <div class="amcom-checkbox-inner"></div>
  </div>
  <div class="amcom-checkbox" checked="checked">
    <div class="amcom-checkbox-inner"></div>
  </div>
  <div class="amcom-checkbox" indeterminate="indeterminate">
    <div class="amcom-checkbox-inner"></div>
  </div>
  <div class="amcom-checkbox validation-error">
    <div class="amcom-checkbox-inner"></div>
  </div>
  <div class="editor-label">
    <label for="test-amcom-checkbox">Test Checkbox</label>
  </div>
  <div class="editor-field">
    <div class="amcom-checkbox" id="test-amcom-checkbox">
      <div class="amcom-checkbox-inner"></div>
    </div>
  </div>
  <table>
    <tbody>
      <tr>
        <td>In a table:</td>
        <td class="narrow">
          <div class="amcom-checkbox">
            <div class="amcom-checkbox-inner"></div>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>
<div class="normal-checkbox">
  <input type="checkbox" class="solo"/>
  <input type="checkbox" class="solo" checked="checked" />
  <input type="checkbox" class="solo indeterminate" />
  <div class="editor-label">
    <label for="test-checkbox">Test Checkbox</label>
  </div>
  <div class="editor-field">
    <input type="checkbox" class="field" id="test-checkbox" />
  </div>
  
  <table>
    <tbody>
      <tr>
        <td>In a table:</td>
        <td class="narrow">
          <input type="checkbox" class="tabled"/>
        </td>
      </tr>
    </tbody>
  </table>
</div>

CSS

* { margin: 0, padding: 0; }
ul { padding-left: 0; }
body { background-color: #FFFFFF; }
table { width: auto; }
.editor-label { float: left; clear: left; margin-right: 0.5em; }
.editor-field { float: left; clear: right; }

.amcom-checkbox 
{
  background-color: white;
  border: 1px solid #888888;
  display: inline-block;
  height: 11px;
  opacity: 0.8;
  width: 11px;
}

.amcom-checkbox:hover
{
  opacity: 1;
}

.amcom-checkbox-inner
{
background-image: linear-gradient(left top, #CCCCCC 28%, #EDEDED 61%);
background-image: -o-linear-gradient(left top, #CCCCCC 28%, #EDEDED 61%);
background-image: -moz-linear-gradient(left top, #CCCCCC 28%, #EDEDED 61%);
background-image: -webkit-linear-gradient(left top, #CCCCCC 28%, #EDEDED 61%);
background-image: -ms-linear-gradient(left top, #CCCCCC 28%, #EDEDED 61%);

background-image: -webkit-gradient(
    linear,
    left top,
    right bottom,
    color-stop(0.28, #CCCCCC),
    color-stop(0.61, #EDEDED)
);
  border: 1px solid #AEB3B9;
  height: 7px;
  width: 7px;
  margin: 1px;
}

.validation-error .amcom-checkbox-inner {
background-image: linear-gradient(right bottom, #B84444 28%, #CF8484 61%);
background-image: -o-linear-gradient(right bottom, #B84444 28%, #CF8484 61%);
background-image: -moz-linear-gradient(right bottom, #B84444 28%, #CF8484 61%);
background-image: -webkit-linear-gradient(right bottom, #B84444 28%, #CF8484 61%);
background-image: -ms-linear-gradient(right bottom, #B84444 28%, #CF8484 61%);

background-image: -webkit-gradient(
    linear,
    right bottom,
    left top,
    color-stop(0.28, #B84444),
    color-stop(0.61, #CF8484)
);
border-color: #CF8484;
}
.indeterminate .amcom-checkbox-inner,
[indeterminate] .amcom-checkbox-inner {
background-image: linear-gradient(right bottom, #25598C 28%, #7FC8E4 61%);
background-image: -o-linear-gradient(right bottom, #25598C 28%, #7FC8E4 61%);
background-image: -moz-linear-gradient(right bottom, #25598C 28%, #7FC8E4 61%);
background-image:...

JavaScript

(function($, window, undefined) {
    $.widget("amcom.checkbox", {
        options: {
            autofocus: false,
            checked: false,
            dirty: false,
            disabled: false,
            indeterminate: false,
            required: false,
            value: null
        },
        click: function(e) {
            this._propAttr('checked', !(this.options.checked || this._propAttr('checked')));
            this._propAttr('indeterminate', false);
            this._propAttr('dirty', true);
            this.element.removeClass('validation-error');
        },
        _attrToBool: function(attrName) {
            var raw = this.element.attr(attrName),
                isU = typeof raw === 'undefined',
                isN = raw === null,
                isSet = this.element.attr(attrName) === attrName || this.element.attr(attrName) === true;
            return !isU && !isN && isSet;
        },
        _propAttr: function(attrName, value) {
            if (typeof value === 'undefined') {
                return this.element.prop(attrName);
            }

            var boolValue = typeof value === 'boolean';
            if (boolValue) {
                boolValue = value === true;
                this.element.prop(attrName, boolValue);
                if (boolValue) {
                    this.element.attr(attrName, attrName);
                } else {
                    this.element.removeAttr(attrName);
                }
                this.options[attrName] = value;
                return;
            }

            this.element.prop(attrName, value).attr(attrName, value);
            this.options[attrName] = value;
        },
        _create: function() {
            this._propAttr('autofocus', this._attrToBool('autofocus'));
            this._propAttr('checked', this._attrToBool('checked'));
            this._propAttr('dirty', this.options.dirty);
            this._propAttr('disabled', this._attrToBool('disabled'));
           ...