├── README.md ├── index.html ├── jquery.switchButton.css ├── jquery.switchButton.js └── main.css /README.md: -------------------------------------------------------------------------------- 1 | jQuery-switchButton 2 | =================== 3 | 4 | jQuery iPhone-like switch button meant to be used on a ``````. 5 | 6 | This widget will replace the receiver element with an iPhone-style switch button with two states: "on" and "off". Labels 7 | of the states are customizable, as are their presence and position. The receiver element's "checked" attribute is updated 8 | according to the state of the switch, so that it can be used in a ```
```. 9 | 10 | Demo 11 | ---- 12 | 13 | Check out the demo page here: http://olance.github.io/jQuery-switchButton/ 14 | 15 | 16 | Dependencies 17 | ------------ 18 | 19 | This is a jQuery UI plugin, so you'll need jQuery and jQuery UI. 20 | 21 | 22 | Usage 23 | ----- 24 | 25 | Say this is your markup: 26 | 27 | 28 | 29 |
30 | 31 | You can transform this checkbox to a nice-looking switch button by calling ```switchButton()``` on it: 32 | 33 | options = { /* see below */ }; 34 | $("input#great").switchButton(options); 35 | 36 | By default, this will display a button with "ON" and "OFF" labels on each side of the switch. You can control this and other 37 | parameters at initialization or by calling ```switchButton("option", "optionName", value)```. 38 | Here are the available options: 39 | 40 | checked: undefined // State of the switch 41 | 42 | show_labels: true // Should we show the on and off labels? 43 | labels_placement: "both" // Position of the labels: "both", "left" or "right" 44 | on_label: "ON" // Text to be displayed when checked 45 | off_label: "OFF" // Text to be displayed when unchecked 46 | 47 | width: 25 // Width of the button in pixels 48 | height: 11 // Height of the button in pixels 49 | button_width: 12 // Width of the sliding part in pixels 50 | 51 | clear: true // Should we insert a div with style="clear: both;" after the switch button? 52 | clear_after: null // Override the element after which the clearing div should be inserted (null > right after the button) 53 | 54 | 55 | Styling 56 | ------- 57 | 58 | The button and labels are styled with a few lines of CSS in ```jquery.switchButton.css```. 59 | Have a look at this file and fiddle with it to change the look of you switch button! 60 | 61 | Wordpress users 62 | --------------- 63 | 64 | Have a look at [this answer](http://wordpress.stackexchange.com/questions/108257/how-to-load-jquery-easing-script-in-wordpress/108267#108267?newreg=7700a444aabf4aadbd1819e794d1d6c4) on StackExchange to include jQuery easing functions in order to make this plugin work in Wordpress. 65 | 66 | 67 | License 68 | ------- 69 | 70 | Copyright (c) Olivier Lance - Released under MIT License: 71 | 72 | > Permission is hereby granted, free of charge, to any person 73 | > obtaining a copy of this software and associated documentation 74 | > files (the "Software"), to deal in the Software without 75 | > restriction, including without limitation the rights to use, 76 | > copy, modify, merge, publish, distribute, sublicense, and/or sell 77 | > copies of the Software, and to permit persons to whom the 78 | > Software is furnished to do so, subject to the following 79 | > conditions: 80 | > 81 | > The above copyright notice and this permission notice shall be 82 | > included in all copies or substantial portions of the Software. 83 | > 84 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 86 | > OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 87 | > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 88 | > HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | > WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 90 | > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 91 | > OTHER DEALINGS IN THE SOFTWARE. 92 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery UI Switch Button Demo - Olivier Lance 5 | 6 | 7 | 8 | 9 | 10 |
11 | Fork me on GitHub 12 | 13 |

jQuery UI iPhone-like Switch Button Demo

14 | 15 |

16 | This widget will replace the receiver element with an iPhone-style switch 17 | button with two states: "on" and "off". Labels of the states are customizable, 18 | as are their presence and position. The receiver element's "checked" attribute 19 | is updated according to the state of the switch, so that it can be used in 20 | a <form>, on a checkbox input for instance. 21 |

22 | 23 |

24 | This widget has been made to answer my specific needs, so there's room for 25 | improvement here and there, but it does the job for me as it is. 26 |

27 | 28 | 29 |

Basic usage

30 | 31 |

32 | Using the following markup: 33 |

34 | 35 |
 36 | <input type="checkbox" value="1" checked>
37 | 38 |

39 | You can simply call switchButton() without any 40 | options on the checkbox element, and you'll get that: 41 |

42 | 43 |
44 | 45 |
46 | 47 |

48 | The widget's elements are floated, so you must wrap the checkbox in its own 49 | <div> if you want to inline it with some 50 | text: 51 |

52 | 53 |
 54 | It is
 55 | <div class="switch-wrapper">
 56 |   <input type="checkbox" value="1" checked>
 57 | </div>
 58 | !
59 | 60 |

61 | Apply some styles to the wrapping <div> and 62 | everything will look perfect: 63 |

64 | 65 |
 66 | .switch-wrapper {
 67 |   display: inline-block;
 68 |   position: relative;
 69 |   top: 3px;
 70 | }
71 | 72 | 73 |
74 | It is 75 |
76 | 77 |
78 | ! 79 |
80 | 81 | 82 |

Playing with options

83 | 84 |

Labels texts

85 |

86 | The first thing you might want to do, is changing the labels texts. The 87 | on_label and off_label 88 | options allow you to do that: 89 |

90 | 91 |
 92 | $("input[type=checkbox]").switchButton({
 93 |   on_label: 'yes',
 94 |   off_label: 'no'
 95 | });
96 | 97 |
98 | I want to break free: 99 |
100 | 101 |
102 |
103 | 104 | 105 |

Default state

106 |

107 | The widget will use the checked attribute of the 108 | receiver to determine the initial state of the switch.
109 | However, you can force it to be on or off by specifying it in the options: 110 |

111 | 112 |
113 | // Force the checked property to false, whatever state it is in initially
114 | $("input[type=checkbox]").switchButton({
115 |   checked: false
116 | });
117 | 118 |
119 | 120 |
121 | 122 | 123 |

Other labels options

124 |

125 | Maybe you'd like to display the button without any label at all: 126 |

127 | 128 |
129 | $("input[type=checkbox]").switchButton({
130 |   show_labels: false
131 | });
132 | 133 |
134 | 135 |
136 | 137 |

138 | Or display them on one side only: 139 |

140 | 141 |
142 | $("input[type=checkbox]").switchButton({
143 |   labels_placement: "right"
144 | });
145 | 146 |
147 | 148 |
149 | 150 |
151 | $("input[type=checkbox]").switchButton({
152 |   labels_placement: "left"
153 | });
154 | 155 |
156 | 157 |
158 | 159 | 160 |

Slider options

161 |

162 | You can customize the size of the slider and the sliding element: 163 |

164 | 165 |
166 | $("input[type=checkbox]").switchButton({
167 |   width: 100,
168 |   height: 40,
169 |   button_width: 50
170 | });
171 | 172 |
173 | 174 |
175 | 176 |
177 | $("input[type=checkbox]").switchButton({
178 |   width: 100,
179 |   height: 40,
180 |   button_width: 70
181 | });
182 | 183 |
184 | 185 |
186 | 187 |

188 | Note that the font-size of the labels for both 189 | examples above have been changed in the CSS. 190 |

191 |
192 | 193 | 194 | 195 | 196 | 197 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /jquery.switchButton.css: -------------------------------------------------------------------------------- 1 | .switch-button-label { 2 | float: left; 3 | 4 | font-size: 10pt; 5 | cursor: pointer; 6 | } 7 | 8 | .switch-button-label.off { 9 | color: #adadad; 10 | } 11 | 12 | .switch-button-label.on { 13 | color: #0088CC; 14 | } 15 | 16 | .switch-button-background { 17 | float: left; 18 | position: relative; 19 | 20 | background: #ccc; 21 | border: 1px solid #aaa; 22 | 23 | margin: 1px 10px; 24 | 25 | -webkit-border-radius: 4px; 26 | -moz-border-radius: 4px; 27 | border-radius: 4px; 28 | 29 | cursor: pointer; 30 | } 31 | 32 | .switch-button-button { 33 | position: absolute; 34 | 35 | left: -1px; 36 | top : -1px; 37 | 38 | background: #FAFAFA; 39 | border: 1px solid #aaa; 40 | 41 | -webkit-border-radius: 4px; 42 | -moz-border-radius: 4px; 43 | border-radius: 4px; 44 | } 45 | -------------------------------------------------------------------------------- /jquery.switchButton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jquery.switchButton.js v1.0 3 | * jQuery iPhone-like switch button 4 | * @author Olivier Lance 5 | * 6 | * Copyright (c) Olivier Lance - released under MIT License {{{ 7 | * 8 | * Permission is hereby granted, free of charge, to any person 9 | * obtaining a copy of this software and associated documentation 10 | * files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, 12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the 14 | * Software is furnished to do so, subject to the following 15 | * conditions: 16 | 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | * }}} 30 | */ 31 | 32 | /* 33 | * Meant to be used on a , this widget will replace the receiver element with an iPhone-style 34 | * switch button with two states: "on" and "off". 35 | * Labels of the states are customizable, as are their presence and position. The receiver element's "checked" attribute 36 | * is updated according to the state of the switch, so that it can be used in a
. 37 | * 38 | */ 39 | 40 | (function($) { 41 | 42 | $.widget("sylightsUI.switchButton", { 43 | 44 | options: { 45 | checked: undefined, // State of the switch 46 | 47 | show_labels: true, // Should we show the on and off labels? 48 | labels_placement: "both", // Position of the labels: "both", "left" or "right" 49 | on_label: "ON", // Text to be displayed when checked 50 | off_label: "OFF", // Text to be displayed when unchecked 51 | 52 | width: 25, // Width of the button in pixels 53 | height: 11, // Height of the button in pixels 54 | button_width: 12, // Width of the sliding part in pixels 55 | 56 | clear: true, // Should we insert a div with style="clear: both;" after the switch button? 57 | clear_after: null, // Override the element after which the clearing div should be inserted (null > right after the button) 58 | on_callback: undefined, //callback function that will be executed after going to on state 59 | off_callback: undefined //callback function that will be executed after going to off state 60 | }, 61 | 62 | _create: function() { 63 | // Init the switch from the checkbox if no state was specified on creation 64 | if (this.options.checked === undefined) { 65 | this.options.checked = this.element.prop("checked"); 66 | } 67 | 68 | this._initLayout(); 69 | this._initEvents(); 70 | }, 71 | 72 | _initLayout: function() { 73 | // Hide the receiver element 74 | this.element.hide(); 75 | 76 | // Create our objects: two labels and the button 77 | this.off_label = $("").addClass("switch-button-label"); 78 | this.on_label = $("").addClass("switch-button-label"); 79 | 80 | this.button_bg = $("
").addClass("switch-button-background"); 81 | this.button = $("
").addClass("switch-button-button"); 82 | 83 | // Insert the objects into the DOM 84 | this.off_label.insertAfter(this.element); 85 | this.button_bg.insertAfter(this.off_label); 86 | this.on_label.insertAfter(this.button_bg); 87 | 88 | this.button_bg.append(this.button); 89 | 90 | // Insert a clearing element after the specified element if needed 91 | if(this.options.clear) 92 | { 93 | if (this.options.clear_after === null) { 94 | this.options.clear_after = this.on_label; 95 | } 96 | $("
").css({ 97 | clear: "left" 98 | }).insertAfter(this.options.clear_after); 99 | } 100 | 101 | // Call refresh to update labels text and visibility 102 | this._refresh(); 103 | 104 | // Init labels and switch state 105 | // This will animate all checked switches to the ON position when 106 | // loading... this is intentional! 107 | this.options.checked = !this.options.checked; 108 | this._toggleSwitch(true); 109 | }, 110 | 111 | _refresh: function() { 112 | // Refresh labels display 113 | if (this.options.show_labels) { 114 | this.off_label.show(); 115 | this.on_label.show(); 116 | } 117 | else { 118 | this.off_label.hide(); 119 | this.on_label.hide(); 120 | } 121 | 122 | // Move labels around depending on labels_placement option 123 | switch(this.options.labels_placement) { 124 | case "both": 125 | { 126 | // Don't move anything if labels are already in place 127 | if(this.button_bg.prev() !== this.off_label || this.button_bg.next() !== this.on_label) 128 | { 129 | // Detach labels form DOM and place them correctly 130 | this.off_label.detach(); 131 | this.on_label.detach(); 132 | this.off_label.insertBefore(this.button_bg); 133 | this.on_label.insertAfter(this.button_bg); 134 | 135 | // Update label classes 136 | this.on_label.addClass(this.options.checked ? "on" : "off").removeClass(this.options.checked ? "off" : "on"); 137 | this.off_label.addClass(this.options.checked ? "off" : "on").removeClass(this.options.checked ? "on" : "off"); 138 | 139 | } 140 | break; 141 | } 142 | 143 | case "left": 144 | { 145 | // Don't move anything if labels are already in place 146 | if(this.button_bg.prev() !== this.on_label || this.on_label.prev() !== this.off_label) 147 | { 148 | // Detach labels form DOM and place them correctly 149 | this.off_label.detach(); 150 | this.on_label.detach(); 151 | this.off_label.insertBefore(this.button_bg); 152 | this.on_label.insertBefore(this.button_bg); 153 | 154 | // update label classes 155 | this.on_label.addClass("on").removeClass("off"); 156 | this.off_label.addClass("off").removeClass("on"); 157 | } 158 | break; 159 | } 160 | 161 | case "right": 162 | { 163 | // Don't move anything if labels are already in place 164 | if(this.button_bg.next() !== this.off_label || this.off_label.next() !== this.on_label) 165 | { 166 | // Detach labels form DOM and place them correctly 167 | this.off_label.detach(); 168 | this.on_label.detach(); 169 | this.off_label.insertAfter(this.button_bg); 170 | this.on_label.insertAfter(this.off_label); 171 | 172 | // update label classes 173 | this.on_label.addClass("on").removeClass("off"); 174 | this.off_label.addClass("off").removeClass("on"); 175 | } 176 | break; 177 | } 178 | 179 | } 180 | 181 | // Refresh labels texts 182 | this.on_label.html(this.options.on_label); 183 | this.off_label.html(this.options.off_label); 184 | 185 | // Refresh button's dimensions 186 | this.button_bg.width(this.options.width); 187 | this.button_bg.height(this.options.height); 188 | this.button.width(this.options.button_width); 189 | this.button.height(this.options.height); 190 | }, 191 | 192 | _initEvents: function() { 193 | var self = this; 194 | 195 | // Toggle switch when the switch is clicked 196 | this.button_bg.click(function(e) { 197 | e.preventDefault(); 198 | e.stopPropagation(); 199 | self._toggleSwitch(false); 200 | return false; 201 | }); 202 | this.button.click(function(e) { 203 | e.preventDefault(); 204 | e.stopPropagation(); 205 | self._toggleSwitch(false); 206 | return false; 207 | }); 208 | 209 | // Set switch value when clicking labels 210 | this.on_label.click(function(e) { 211 | if (self.options.checked && self.options.labels_placement === "both") { 212 | return false; 213 | } 214 | 215 | self._toggleSwitch(false); 216 | return false; 217 | }); 218 | 219 | this.off_label.click(function(e) { 220 | if (!self.options.checked && self.options.labels_placement === "both") { 221 | return false; 222 | } 223 | 224 | self._toggleSwitch(false); 225 | return false; 226 | }); 227 | 228 | }, 229 | 230 | _setOption: function(key, value) { 231 | if (key === "checked") { 232 | this._setChecked(value); 233 | return; 234 | } 235 | 236 | this.options[key] = value; 237 | this._refresh(); 238 | }, 239 | 240 | _setChecked: function(value) { 241 | if (value === this.options.checked) { 242 | return; 243 | } 244 | 245 | this.options.checked = !value; 246 | this._toggleSwitch(false); 247 | }, 248 | 249 | _toggleSwitch: function(isInitializing) { 250 | // Don't toggle the switch if it is set to readonly or disabled, unless it is initializing and animating itself 251 | if( !isInitializing && (this.element.attr('readonly') == 'readonly' || this.element.prop('disabled')) ) 252 | return; 253 | 254 | this.options.checked = !this.options.checked; 255 | var newLeft = ""; 256 | if (this.options.checked) { 257 | // Update the underlying checkbox state 258 | this.element.prop("checked", true); 259 | this.element.change(); 260 | 261 | var dLeft = this.options.width - this.options.button_width; 262 | newLeft = "+=" + dLeft; 263 | 264 | // Update labels states 265 | if(this.options.labels_placement == "both") 266 | { 267 | this.off_label.removeClass("on").addClass("off"); 268 | this.on_label.removeClass("off").addClass("on"); 269 | } 270 | else 271 | { 272 | this.off_label.hide(); 273 | this.on_label.show(); 274 | } 275 | this.button_bg.addClass("checked"); 276 | //execute on state callback if its supplied 277 | if(typeof this.options.on_callback === 'function') this.options.on_callback.call(this); 278 | } 279 | else { 280 | // Update the underlying checkbox state 281 | this.element.prop("checked", false); 282 | this.element.change(); 283 | newLeft = "-1px"; 284 | 285 | // Update labels states 286 | if(this.options.labels_placement == "both") 287 | { 288 | this.off_label.removeClass("off").addClass("on"); 289 | this.on_label.removeClass("on").addClass("off"); 290 | } 291 | else 292 | { 293 | this.off_label.show(); 294 | this.on_label.hide(); 295 | } 296 | this.button_bg.removeClass("checked"); 297 | //execute off state callback if its supplied 298 | if(typeof this.options.off_callback === 'function') this.options.off_callback.call(this); 299 | } 300 | // Animate the switch 301 | this.button.animate({ left: newLeft }, 250, "easeInOutCubic"); 302 | } 303 | 304 | }); 305 | 306 | })(jQuery); 307 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | 5 | font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif; 6 | font-size: 14px; 7 | color: #333; 8 | background-color: #EFEFEF; 9 | } 10 | 11 | .wrapper { 12 | position: relative; 13 | width: 800px; 14 | margin: auto; 15 | padding: 20px 40px; 16 | background: white; 17 | } 18 | 19 | p { 20 | text-align: justify; 21 | max-width: 700px; 22 | } 23 | 24 | h2 { 25 | padding-bottom: 10px; 26 | border-bottom: 1px solid #ccc; 27 | margin-top: 60px; 28 | } 29 | 30 | h3 { 31 | margin-top: 40px; 32 | } 33 | 34 | code, pre { 35 | margin: 0 2px; 36 | padding: 0px 5px; 37 | border: 1px solid #EAEAEA; 38 | background-color: #F8F8F8; 39 | border-radius: 3px; 40 | font-size: 12px; 41 | font-family: Consolas, "Liberation Mono", Courier, monospace; 42 | } 43 | 44 | pre { 45 | max-width: 600px; 46 | padding: 10px; 47 | margin: 20px 0; 48 | } 49 | 50 | .demo::before{ 51 | content: "result"; 52 | display: block; 53 | margin-bottom: 10px; 54 | text-transform: uppercase; 55 | font-size: 10px; 56 | letter-spacing: 1px; 57 | color: #CCC; 58 | border-bottom: 1px solid #DDD; 59 | width: 600px; 60 | padding: 0 20px 5px 0; 61 | } 62 | 63 | .demo { 64 | padding: 20px 0; 65 | } 66 | 67 | .switch-wrapper { 68 | display: inline-block; 69 | position: relative; 70 | top: 3px; 71 | } 72 | 73 | 74 | .slider.demo .switch-button-label { 75 | font-size: 40px; 76 | } 77 | --------------------------------------------------------------------------------