Fun With the Slider Widget


The jQuery Mobile  (jQM) library includes a basic slider widget, which is used to enter numeric values along a continuum. You define minimum and maximum values for the number and jQM creates a track with a handle you can drag back and forth via mouse or touch. This post presents some examples of extending the basic slider to make it more colorful.

For those of you who can’t wait and would like to see the end results first:

Example End Results

Example 1 –  Dynamic Highlight Color

Let’s take a basic slider with data-highlight set to true; but instead of just showing the default theme highlight color, let’s change the highlight color based on the current value of the slider.  The HTML markup is just the standard jQM slider markup wrapped in a DIV container :

<div id="example1" >
  <label for="theSlider1">Highlight Color Changes:</label>
  <input type="range" name="theSlider1" id="theSlider1" min="0" max="100" value="12" data-highlight="true" />
</div>

To change color based on value, we will handle the change event on the input, get the value and update the highlight color based on that value:

HighlightColor($("#theSlider1"));

$("#theSlider1").on("change", function(){
  HighlightColor($(this));
});

function HighlightColor(slider){
  var theVal = slider.val();
  var color = "#0DB8B5";
  if (theVal < 20){
    color = "#D92727";
  } else if (theVal < 40){
    color = "#FC8F12";
  } else if (theVal < 60){
    color = "#FFE433";
  } else if (theVal < 80){
    color = "#6FCC43";
  }        
  slider.closest(".ui-slider").find(".ui-slider-bg").css("background-color", color);        
}

The element that gets the highlight color is a DIV with class .ui-slider-bg included in the .ui-slider DIV that jQM creates when enhancing the slider widget. To make the colors fade into eachother, we can add a small transition time via CSS to the element:

#example1 .ui-slider-bg{
    -webkit-transition:background-color 0.2s;
    transition: background-color 0.2s;
}

Example 2 – Color Graded Track Background

Now let’s take the basic slider data-highlight set to  false and instead provide a multicolored background with labels indicating what the different ranges of the numeric input mean. The markup is again the basic slider but without the data-highlight:

<div id="example2" >
  <label for="theSlider2">Informative Background:</label>
  <input type="range" name="theSlider2" id="theSlider2" min="0" max="200" value="60" />
</div>

Then in code we insert colorful DIVs directly into the track of slider widget:

var colorback  = '<div class="sliderBackColor green">Low</div>';
    colorback += '<div class="sliderBackColor orange">Medium</div>';
    colorback += '<div class="sliderBackColor red">High</div>';

$("#example2 .ui-slider-track").prepend(colorback);

The code creates 3 DIVs. Each has the class sliderBackColor and then a separate class to apply the background color. The DIVS include any text which will label the ranges. Finally we find the track element (.ui-slider-track) and we prepend the DIVs so that they appear below the slider handle. The positioning and coloring of the DIVs is then handled via plain CSS:

.sliderBackColor{
    height: 100%;
    width: 33.33%;    
    float: left;
    color: white;
    text-align: center;
    font-size: 10px;
    font-weight: normal;
    text-shadow: 0px 1px 2px #333;
}
.red { background-color: #BD1550;}
.green { background-color: #8A9B0F;}
.orange { background-color: #E97F02;}

.ui-slider-track > div.sliderBackColor:first-child{
    border-top-left-radius: 0.3125em;
    border-bottom-left-radius: 0.3125em;
}
.ui-slider-track > div.sliderBackColor:last-of-type{
    border-top-right-radius: 0.3125em;
    border-bottom-right-radius: 0.3125em;   
}

As we inserted 3 DIVS, the CSS gives each a width of 33.33% and a left float so that they fill the slider track. The individual color classes assign different background colors to each of the 3 DIVS , and the last 2 rules provide some border radius to the first and last DIVs so they match the slider track rounded corners. The resulting slider looks like this:

example02.jpg

The slider now provides users with some context for the number it represents. A similar way to provide some context in the background is to add tick marks:

example02a.jpg

We also achieve this by inserting DIVs into the slider track. In this example we add 5 DIVs with their labels included in a child SPAN. The DIVs are assigned a class of sliderTickmarks:

var ticks  = '<div class="sliderTickmarks "><span>0%</span></div>';
    ticks += '<div class="sliderTickmarks "><span>25%</span></div>';
    ticks += '<div class="sliderTickmarks "><span>50%</span></div>';
    ticks += '<div class="sliderTickmarks "><span>75%</span></div>';
    ticks += '<div class="sliderTickmarks "><span>100%</span></div>';

$("#example2a .ui-slider-track").prepend(ticks);

The CSS for the tick marks leaves the DIV backgrounds transparent and instead adds a right border to the middle 3 DIVs to show a vertical tick mark. The labels in the inner spans then use relative positioning to move below the track:

.sliderTickmarks{
    -webkit-box-sizing: border-box; 
    box-sizing: border-box;
    height: 100%;
    width: 25%;    
    float: left;
    border-right: 1px solid #888;
}
.sliderTickmarks span{
    position: relative;
    left: 100%;
    top: 125%;
    margin-left: -10px;
    font-size: 12px;
    font-weight: normal;
}
.ui-slider-track > div.sliderTickmarks:first-child{
    border-right: 0;
    width: 0;
}
.ui-slider-track > div.sliderTickmarks:first-child span{
    margin-left: -5px;
}
.ui-slider-track > div.sliderTickmarks:last-of-type{
     border-right: 0;
}

Example 3 – Slider Handle Glow Color

When dragging the slider handle, it glows with a default color to let you know that it is currently active.  Using CSS we can change the glow color, and in combination with the slider’s change handler, we can dynamically update the glow color based on the current value. For the markup we again use the basic slider within a DIV container, but this time we apply a class to the container called glow:

<div id="example3" class="glow">
  <label for="theSlider3">Slider Handle Glow Color:</label>
  <input type="range" name="theSlider3" id="theSlider3" min="0" max="100" value="40" />
</div>

The glow color is set in jQM’s .ui-btn:focus rules using the box-shadow attribute, so we create classes for each desired color and apply them to the slider container DIV. We also apply a transition time so the colors will fade into each other:

#example3 .ui-slider .ui-btn{
    -webkit-transition: box-shadow 0.25s;
    transition: box-shadow 0.25s;
}
.glowBlue .ui-slider .ui-btn:focus {
    box-shadow: 0 0 12px #127A97;
}
.glowYellow .ui-slider .ui-btn:focus {
    box-shadow: 0 0 12px #F9BA15;
}
.glowRed .ui-slider .ui-btn:focus {
    box-shadow: 0 0 12px #BF0C43;
}
.glowGreen .ui-slider .ui-btn:focus {
    box-shadow: 0 0 12px #8EAC00;
}

The code is then similar to example 1 in that we handle the change event, get the current value, determine which color we should use. The only difference is in how we finally set the color:

GlowColor($("#theSlider3"));

$("#theSlider3").on("change", function(){
  GlowColor($(this));
});

function GlowColor(slider){
  var theVal = slider.val();
  var glowClass = "glowRed";
  if (theVal < 25){
    glowClass = "glowGreen";
  } else if (theVal < 50){
    glowClass = "glowBlue";
  } else if (theVal < 75){
    glowClass = "glowYellow";
  }      
  slider.parents(".glow").removeClass("glowBlue glowYellow glowRed glowGreen").addClass(glowClass);    
}

We find the parent with the glow class, remove any previous color classes and then add the desired current color class.

Example 4 – Full-Width Slider with Value on the Handle

Sometimes we want a full-width slider with no input showing to the left. In this case it might be useful to display the current value of the slider on the handle itself. jQM provides the data-show-value attribute for this, but because in the next example we will display something other than the value, we will use our own code in this example. For the markup we stay with the standard slider in a container DIV and assign a class of full-width-slider to the container:

<div id="example4" class="example full-width-slider">
  <label for="theSlider4">Full Width Value on Handle:</label>
  <input type="range" name="theSlider4" id="theSlider4" min="0" max="100" value="75" />
</div>

Then to make the slider full-width, we use CSS to hide the input and set the track margin:

.full-width-slider input {
    display: none;
}
.full-width-slider .ui-slider-track {
    margin-left: 15px;
}

Finally in code, we handle the change event, get the current value and make it the text of the handle DOM element:

$("#theSlider4").closest(".ui-slider").find(".ui-slider-handle").text($("#theSlider4").val());
$("#theSlider4").on("change", function(){
  $(this).closest(".ui-slider").find(".ui-slider-handle").text($(this).val());
});

Example 5 – Multi-State Flip Switch

In this final example, we will tie together the concepts from the previous examples and add a couple of new tweaks to create a 5 position switch. For the markup, our slider is given a min value of 1 and a max value of 5 so that each value will represent a position of the switch. The containing div is assigned the classes of full-width-slider and glow so that the input on the left is hidden, and we can dynamically update the glow color as we did in previous examples:

<div id="example5" class="example full-width-slider glow">
  <label for="theSlider5">Multi-state Flip Switch:</label>
  <input type="range" name="theSlider5" id="theSlider5" min="1" max="5" value="1"  />
</div>

In CSS, we make the slider handle wider so we can write the switch position on the handle and give it a small transition time so when the user clicks the track, the switch movement to the new position is animated. The rest of the CSS should look familiar from the previous examples:

#example5 .ui-slider-handle{
    -webkit-transition:left 0.1s;
    transition: left 0.1s;
    width: 60px;
    margin-left: -30px;
}
.switch5BackColor{
    height: 100%;
    width: 20%;    
    float: left;
    color: white;
    text-align: center;
    font-size: 10px;
    font-weight: normal;
    text-shadow: 0px 1px 2px #333;
}
.ui-slider-track > div.switch5BackColor:first-child{
    border-top-left-radius: 0.3125em;
    border-bottom-left-radius: 0.3125em;
}
.ui-slider-track > div.switch5BackColor:last-of-type{
    border-top-right-radius: 0.3125em;
    border-bottom-right-radius: 0.3125em;   
}
.pos1 { background-color: #BD2A33;}
.pos2 { background-color: #D6AA26;}
.pos3 { background-color: #93A31C;}
.pos4 { background-color: #408156;}
.pos5 { background-color: #30374F;}
.pos1glow .ui-slider .ui-btn:focus{ box-shadow: 0 0 12px #BD2A33;}
.pos2glow .ui-slider .ui-btn:focus{ box-shadow: 0 0 12px #D6AA26;}
.pos3glow .ui-slider .ui-btn:focus{ box-shadow: 0 0 12px #93A31C;}
.pos4glow .ui-slider .ui-btn:focus{ box-shadow: 0 0 12px #408156;}
.pos5glow .ui-slider .ui-btn:focus{ box-shadow: 0 0 12px #30374F;}

In code, we insert 5 DIVs into the track as we did in example 2. Then we handle the slider change event and dynamically update the handle glow color (example 3) and the handle text (example 4). The one new trick added in this example is that we position the handle depending on the current value because we want the handle to align nicely with the background DIVs. Therefore, when the switch is set to 1, instead of having the handle all the way on the left, we move it to 10% (the center point of the first background DIV). Similar offsets are calculated for each value, except for 3 which is already at 50%:

var switchBack  = '<div id="sw1" class="switch5BackColor pos1">pos 1</div>';
  switchBack += '<div id="sw2" class="switch5BackColor pos2">pos 2</div>';
  switchBack += '<div id="sw3" class="switch5BackColor pos3">pos 3</div>';
  switchBack += '<div id="sw4" class="switch5BackColor pos4">pos 4</div>';
  switchBack += '<div id="sw5" class="switch5BackColor pos5">pos 5</div>';    
$("#example5 .ui-slider-track").prepend(switchBack);
PositionSwitchHandle($("#theSlider5"));
$("#theSlider5").on("change", function(){
  PositionSwitchHandle($(this));
});

function PositionSwitchHandle(slider){
  var theVal = slider.val();
  var ml = "50%";
  var glowClass = "pos3glow";
  var theText = "pos 3"
   if (theVal <= 1){
    ml = "10%";
    glowClass = "pos1glow";
    theText = "pos 1"
  } else if (theVal == 2){
    ml = "30%";
    glowClass = "pos2glow";
    theText = "pos 2"
  } else if (theVal == 4){
    ml = "70%";
    glowClass = "pos4glow";
    theText = "pos 4"
  } else if (theVal >= 5){
    ml = "90%";
    glowClass = "pos5glow";
    theText = "pos 5"
  }
  slider.closest(".ui-slider").find(".ui-slider-handle").css("left", ml).text(theText);  
  slider.parents(".glow").removeClass("pos1glow pos2glow pos3glow pos4glow pos5glow").addClass(glowClass);
}

UPDATE 5/28/2014

For the 5 position flip switch, sometimes clicking or tapping near the border between 2 positions did not switch to the correct position. I have updated the demo with a click handler for each inserted DIV to make sure the switch is moved to the correct position;

 $("#example5 .ui-slider-track").on('click', '.switch5BackColor', function(e){
     //make sure switch is in correct position
     var val = 1;
     if ($(this).hasClass("pos2")) {val = 2;}
     if ($(this).hasClass("pos3")) {val = 3;}
     if ($(this).hasClass("pos4")) {val = 4;}
     if ($(this).hasClass("pos5")) {val = 5;}
     $("#theSlider5").val(val).slider( "refresh" );
 });

UPDATE 11/19/2014

Commentor, Anshuyi, has noted that with version 1.4.5 of jQuery Mobile, the 5 position flip switch no longer positions the thumb correctly. It seems that the easiest fix is to use the left-margin instead of the left position to correctly place the thumb. Calculate the appropriate left margin in percent and also reposition the thumb when the page is shown, the window is resized, or the orientation is changed

$("#example5 .ui-slider-track").on('click', '.switch5BackColor', function(e){
     //make sure switch is in correct position
     var val = 1;
     if ($(this).hasClass("pos2")) {val = 2;}
     if ($(this).hasClass("pos3")) {val = 3;}
     if ($(this).hasClass("pos4")) {val = 4;}
     if ($(this).hasClass("pos5")) {val = 5;}
     $("#theSlider5").val(val).slider( "refresh" ).trigger("change");
 });

function PositionSwitchHandle(slider){
   var $handle = slider.closest(".ui-slider").find(".ui-slider-track");
   var handleWidth = $handle.width();
   var mgPct = (30 * 100) / handleWidth; //half thumb handle in pct of track
   var theVal = parseInt(slider.val());
   var margLeft = -mgPct;
   var glowClass = "pos3glow";
   var theText = "pos 3"
   if (theVal <= 1){
     margLeft = 10 - mgPct;
     glowClass = "pos1glow";
     theText = "pos 1"
   } else if (theVal == 2){
     margLeft = 5 - mgPct;
     glowClass = "pos2glow";
     theText = "pos 2"
   } else if (theVal == 4){
     margLeft = -5 - mgPct;
     glowClass = "pos4glow";
     theText = "pos 4"
   } else if (theVal >= 5){
     margLeft = -10 - mgPct;
     glowClass = "pos5glow";
     theText = "pos 5"
   }
   slider.closest(".ui-slider").find(".ui-slider-handle").css("marginLeft", margLeft + "%").text(theText); 
   slider.parents(".glow").removeClass("pos1glow pos2glow pos3glow pos4glow pos5glow").addClass(glowClass);
}

$(document).on( "pagecontainershow", function(){
   PositionSwitchHandle($("#theSlider5")); 
});
$(window).on("resize orientationchange", function(){
   PositionSwitchHandle($("#theSlider5"));
});

DEMO

I have created a single jsFiddle with all these examples included so you can play with the code and maybe come up with your own creative ways to use the slider widget. Have fun!

jQM 1.4 Slider Widget Demo

Updated for 1.4.5:

jQM 1.4.5 Slider Widget Demo

Buy Me A Coffee :) @ ko-fi.com

Advertisements

21 thoughts on “Fun With the Slider Widget

  1. Hi, great stuff ; could you show how to remove the handle off the track, or make it invisible;
    I have tried to style it inline with no success………
    ………style”.ui-slider-handle{display:none;}”……………
    Kind regards.

  2. Hmm. somehow i tried your example and it behaves differently in chrome and in ie. In ie it is ok, everything is like i wanted it to be. But in Chrome, the colour does not appear right and the pos1 pos2.. etc writings that supposed to be inside the slider bar, appears as writing in the bottom of the slider…

  3. Hi Erik.

    Your brilliant post, “Use slider to select a time in Jquery Mobile,” What is neede to use your method with the Rangeslider, too?
    I have a need (as do others, probably) to use the Jquery Mobile Rangeslider to set a time range when a process is inactive.
    Thanks, in advance.

    stackoverflow(dot)com/questions/5501536/jquery-mobile-slider-change-event

  4. ashok, to change the background color of the handle, you can use CSS targetting the .ui-slider-handle class: .ui-slider-handle{ background-color: #127A97; }

  5. Very good work!

    But it work fine if JQuery Mobile version is 1.4.2. But if you upgrade JQuery Mobile version to latest 1.4.5, then the last slider doesn’t work fine and the behavior is very strange.

    We need JQuery Mobile 1.4.5 as latest version fixed many bugs for iOS8 !!

    Can you help replace JQuery Mobile version with latest version 1.4.5, and fix the problem in last slider.

    Thanks

  6. Hi again Erik,

    Okay as suspected I’m having a few problems! I don’t have a StackOverflow account, is it possible I can mail you? Basically everything works fine until I place your code into my JQM page. I need to insert the ‘slider’ at a particular point on my page. My page already has and so I have removed these tags from your code. As soon as I do, the styling breaks and the hidden div’s are no longer hidden. The modified code…


    I am DIV number 1
    I am DIV number 2
    I am DIV number 3
    I am DIV number 4
    I am DIV number 5

    I created a new doc based on the JSFIDDLE code for testing purposes. I uploaded and tested on my mobile and all worked fine. So not sure why when I include your code in my existing page, something breaks!

    Once again your help would be much appreciated.

    Regards,
    Damian

  7. Erik, you are a legend! Thank you for your prompt reply and solution. I’m going to play around a bit with it, if I have any problems I’ll let you know.

    Thanks again.

  8. Hi Erik,

    Thanks for the post. I’d really like to use example 5 (Example 5 – Multi-State Flip Switch) to show and hide multiple div’s. Any suggestions as to how to do this?

    Your help would be greatly appreciated.

  9. Simon, can you create a jsFiddle that reproduces the problem? By seeing all your code, perhaps I can help. Also, you can try posting a question at stackoverflow with the jquery-mobile tag.

  10. Really good work, I use it too display the average value on a rating slider in an HTML form. But when I press the send button, a second (and third, fourth…) line is drawn below. See Screenshot (http://abload.de/img/slider2zjvx.png). Do you have any idea to precent this? Thank you for your help.
    Kind regards from Germany

    Simon

Drop me a line or two ;)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s