Toggle Switch

by hiddenloop

HTML

<div class="toggle toggle-off" id="foo">
    <div class="slide">
        <label>ON
            <input name="toggle" value="1" type="radio" id="t1" />
        </label>
        <div class="afford"></div>
        <label>OFF
            <input name="toggle" value="0" checked="true" type="radio" id="t2" />
        </label>
    </div>
</div>
<div class="toggle toggle-x toggle-off" id="bar">
    <div class="slide">
        <label>ON
            <input name="toggle" value="1" type="radio" id="t1" />
        </label>
        <div class="afford"></div>
        <label>OFF
            <input name="toggle" value="0" checked="true" type="radio" id="t2" />
        </label>
    </div>
</div>

CSS

body {
    font: normal 14px/1.23"Ubuntu Beta", UbuntuBeta, Ubuntu, "Bitstream Vera Sans", "DejaVu Sans", Tahoma, sans-serif;
}
label {
    font-weight:500;
    font-size:10px;
}
.yui3-toggleswitch {
    display:inline-block;
}
.toggle {
    color:rgb(90, 90, 90);
    display:inline-block;
    background:#eee;
    border-radius:3px;
    -webkit-box-shadow: inset 0 1px 3px 1px rgba(60, 60, 60, 0.1);
    box-shadow: inset 0 1px 3px 1px rgba(60, 60, 60, 0.1);
    overflow:hidden;
    position:relative;
    border:1px solid rgba(90, 90, 90, 0.3);
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
}
.slide {
    width: 28px;
    padding:3px 0;
    height:24px;
    position:relative;
    top:0;
    left:0;
    -webkit-transition: all 60ms cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -moz-transition: all 60ms cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -ms-transition: all 60ms cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -o-transition: all 60ms cubic-bezier(0.250, 0.250, 0.750, 0.750);
    transition: all 60ms cubic-bezier(0.250, 0.250, 0.750, 0.750);
    /* linear */
    -webkit-transition-timing-function: cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -moz-transition-timing-function: cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -ms-transition-timing-function: cubic-bezier(0.250, 0.250, 0.750, 0.750);
    -o-transition-timing-function: cubic-bezier(0.250, 0.250, 0.750, 0.750);
    transition-timing-function: cubic-bezier(0.250, 0.250, 0.750, 0.750);
    /* linear */
}
.toggle-off .slide {
    top:-16px;
}
.toggle-off .afford {
    background:rgb(90, 90, 90);
}
.toggle input[type=radio] {
    display:none;
}
.toggle label {
    line-height:14px;
    display:block;
    text-align: center;
    text-shadow: 0px 1px 0px #ffffff;
}
.afford {
    border-radius:2px;
    background:rgb(221, 71, 19);
    height:10px;
    width:24px;
    margin:0 0 2px 1px;
    border:1px solid rgba(80, 80, 80, 0.5);
}
.toggle-x {
    overflow:hidden;
   ...

JavaScript

// TODO no javascript = no CSS
// TODO add the affordance and slide wrapper via renderUI?
// TODO handle drag, touchStart

YUI.add('toggle', function (Y) {

    var ToggleSwitch = Y.Base.create('toggleSwitch', Y.Widget, [], {
        bindUI: function () {
            var bb = this.get('boundingBox');
            Y.on("click", Y.bind(this._onClick, this), bb);

            this.on("stateChange", this._onStateChange);
        },
        syncUI: function () {
            var state = this.get('state');
            this._setClass(state);
        },
        _onClick: function (e) {
            var state = this.get('state');
            this.set('state', !state);
            e.preventDefault();
        },
        _setClass: function (state) {
            var cb = this.get('contentBox');
            if (state) {
                cb.removeClass('toggle-off');
            } else {
                cb.addClass('toggle-off');
            }
        },
        _onStateChange: function (e) {
            var truthyNode = this.get('truthyIn'),
                falseyNode = this.get('falseyIn');

            this._setClass(e.newVal);

            if (e.newVal) {
                truthyNode.setAttribute('checked', true);
                falseyNode.setAttribute('checked', false);
            } else {
                truthyNode.setAttribute('checked', false);
                falseyNode.setAttribute('checked', true);
            }


        }
    }, {
        ATTRS: {
            state: {
                value: !0
            },
            truthyIn: {
                value: ''
            },
            falseyIn: {
                value: ''
            }
        },
        HTML_PARSER: {
            truthyIn: '#t1',
            falseyIn: '#t2',
            state: function (srcNode) {
                var val = srcNode.one("input[checked=true]").get("value");
                return +val;
            }
        }
    });

    Y.namespace("U1").ToggleSwitch = ToggleSwitch;

}, '0.1', {
   ...