I’m generally a big fan of jQuery mobile. I think it’s an ambitious project and it’s got some areas that could be improved, but I’m glad we’re contributing and think it’s going to be a huge boon for mobile web applications as they get bigger and bigger. But building PhoneGap applications with jQuery Mobile is a bit problematic partly because the goal for the project is “Delivering top-of-the-line JavaScript and a unified User Interface across the most-used smartphone web browsers…” and partly because jQuery Mobile can be tough to really customize if you want a specific look and feel. One of the things I wanted for something I’m working on is a slider that is a bit more boxy than the traditional slider used with jQuery Mobile. Some of this might have been possible with customizing the jQuery Mobile theme but I wanted to see what it would take to build my own from scratch.
This example is part of an app that’s using Backbone.js so I won’t post a working example because the Backbone.js infrastructure makes it kind of tough to strip out just the toggle button part. I’ll post the whole thing later, but wanted to show the general process.
The Look and Feel
To set it up I wrapped a div tag around a select tag with a couple of options. The div tag provided the border so it ended up being the track that the sider went along. This makes it pretty easy to customize the look and feel while still being very nicely degraded into a regular HTML select box.
<div id="toggle" class="toggleoff">
<select name="activetoggle" id="activetoggle" class="selectoff">
<option value="all">All</option>
<option value="active">Active</option>
</select>
</div>
Initially both the div and the select start with “off” classes. At this point the CSS starts to take over and create a more slider-looking button. There is a cool -webkit-appearance property that can be used on the slider to give it some instantaneous look/feel. But for the most part I rely on -webkit-border-image to customize the look and feel of the slider button. The CSS for the toggle button itself, the div tag, and the off states give us a basic looking toggle with no real toggle functionality because it behaves just like a regular HTML select box.

Toggle button off state
select {
-webkit-appearance: push-button;
margin-top: 0px;
margin-bottom: 0px;
height: 50px;
width: 155px;
border-style: solid;
border-color: #cdcdcd;
border-width: 1px;
color: #555;
font-size: 25px;
overflow: hidden;
padding-top: 2px;
padding-bottom: 1px;
white-space: nowrap;
text-align: center;
}
.selectoff {
-webkit-border-image: url( ../assets/button.up.png ) 4 4 4 4 stretch stretch;
padding-left: 60px;
}
#toggle {
margin-left: 5px;
margin-right: 5px;
margin-top: 5px;
height: 50px;
width: 312px;
-webkit-border-radius: 2px;
-webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
border: 2px solid #cdcdcd;
}
.toggleoff {
padding-left: 158px;
background-image: -webkit-linear-gradient(#ffffff, #e7e7e7);
}
I have the benefit of using absolute positioning because I’m building this for an iPhone, but the CSS is pretty straightforward. I’ve got some padding-left properties so I can control how the text looks and where the actual toggle button appears within the div tag. This is why this particular strategy works. When I move between states I’m just going to change the position of the toggle button, I’m not actually doing anything with the select object itself other than changing how it looks and where it is. Here are the “on” classes.
.selecton {
-webkit-border-image: url(../assets/button.down.png) 4 4 4 4 stretch stretch;
padding-left: 30px;
}
.toggleon {
padding-left: 0px;
background-image:-webkit-linear-gradient(#bccead, #cbdfba);
}
Just a couple of small changes to gradients and backgrounds so that when our button is on or active, it looks like this:

Toggle button on state
Functionality
Now that the CSS classes are set up I used jQuery to first add/remove the classes I wanted and finally set the value of the select box programatically. As I mentioned, this is using Backbone.js so the code may look a bit odd.
onMouseDown:function(event){
event.preventDefault();
if(this.displayingAll) {
$("#activetoggle").removeClass("selectoff");
$("#activetoggle").addClass("selecton");
$("#toggle").removeClass("toggleoff");
$("#toggle").addClass("toggleon");
$("#activetoggle").val("active");
} else {
$("#activetoggle").removeClass("selecton");
$("#activetoggle").addClass("selectoff");
$("#toggle").removeClass("toggleon");
$("#toggle").addClass("toggleoff");
$("#activetoggle").val("all");
}
My Backbone view has a variable, displayingAll, which I set to either true or false depending on what is currently visible. It helps track which classes need to be added/removed. But the first, and probably most important thing, is that I’m capturing the event and keeping it from doing anything. I don’t want the default select behavior at all so I can trap it and make sure it doesn’t keep doing the rest of its work. That means no pop up where the user can select values. Instead I go through and swap out the on/off classes to change the look of my button. Finally I use the val() method to set the value of the select so that what the screen is showing is the actual value of the select input.
So now the slider is working but we haven’t done any animation. So right now the slider just jumps back and forth. It works but it isn’t all that pretty. Luckily CSS3 is pretty awesome and we can leverage the very powerful -webkit-transition to help us out.
Animation
Animation for this example is insanely simple. Using the -webkit-transition CSS property we can listen for changes in the DOM on a specific property and whenever that property changes we can play a specific transition. The way I have set this up is that I’m changing the padding-left property between on/off classes so that’s the one we have to listen for.
Quick sidenote: I struggled with this for a bit. At first I was using the align property of the div to move the toggle button back and forth. That had the benefit of being able to scale better for multiple pixel-widths. The button would move back and forth just fine but there wasn’t a way to animate the align property that I found, which makes sense. So to do animation I had to use a value that could be animated and padding-left ended up being a decent option.
In order to get the animation to trigger we have to add a single CSS property to the #toggle div tag:
-webkit-transition: padding-left 250ms ease-out;
So whenever the padding-left property changes (on a Webkit browser) a quarter of a second ease-out transition will play and move the toggle button back and forth. Under the hood we’re changing the value of the select so that if we have to rely on that value it’s all in sync while still creating a very specific look-and-feel for our toggle button.
I realize this isn’t entirely helpful without a working demo and I’ll work on getting a jsFiddle or something up to show it but I’m working on some other bits of the project and want to be able to share the whole thing when it’s done. One of the main things I learned: CSS3 transitions aren’t entirely intuitive when coming from the Flash world, but they’re very powerful.