Once upon a time, a student had to implement a min/max dual range slider in her project. She cleverly searched, copy-and-pasted a solution on the Internet. But when tasked to customize it, she went into a “don’t know how” trance. Well, let Master Coffee walk you through the mechanics, so you can customize it as much as you like – Let’s go.
CODE DOWNLOAD
I have released this under the MIT license, feel free to use it in your own project – Personal or commercial. Some form of credits will be nice though. 🙂
VIDEO TUTORIAL
DUAL RANGE SLIDER DEMO
My Wordpess theme is messing up the styles a little bit… Download the zip above and see the “clean” version if you want.
THUMB & TRACK
Before we proceed, here’s a quick “terminology” for the beginners.
- The red round button you drag around is called the “thumb”.
- The grey horizontal line in the background is called the “track”.
PART 1) THE HTML
<div class="drange">
<input type="range" min="1" max="100" value="20">
<input type="range" min="1" max="100" value="70">
<div class="dmin">0</div>
<div class="dmax">0</div>
</div>
- Start by creating a
<div class="drange">
container. - Insert 2
<input type="range">
sliders. One for the “min”, another for the “max”. - Lastly, this is kind of optional. But if you want to display the current value, also add
<div class="dmin"> <div class="dmax">
.
PART 2) THE CSS – STACK THE SLIDERS
/* (PART A) STACK RANGE SLIDERS */
.drange {
position: relative;
}
.drange input[type="range"] {
position: absolute;
width: 100%;
pointer-events: none;
}
.drange input[type=range]::-webkit-slider-thumb {
pointer-events: all;
}
.drange input[type=range]::-moz-range-thumb {
pointer-events: all;
}
The first thing we do, stack the range sliders on top of each other.
- Set the container to
position: relative
, and the sliders toposition: absolute
. - That’s about it, but only the top slider can be clicked with this “stacking”. To work around, we play with the pointer events.
- Set both sliders to
pointer-events: none
. - But set the thumb to
pointer-events: all
.
- Set both sliders to
PART 3) THE CSS – HIDE DEFAULT SLIDER STYLES
/* (PART B) WRAPPER : CENTER SLIDERS & DIMENSIONS */
.drange {
display: flex; align-items: center;
max-width: 400px; height: 50px;
margin: 10px 10px 20px 10px;
}
/* (PART C) HIDE DEFAULT SLIDER STYLES */
.drange input[type=range] {
appearance: none;
background: none;
}
.drange input[type=range]::-webkit-slider-thumb {
appearance: none;
}
.drange input[type=range]:focus {
outline: none;
}
This section is pretty self-explanatory. To customize the sliders, we have to hide the default styles for the thumb and track.
PART 4) THE CSS – CUSTOM RANGE SLIDER
/* (PART D) CUSTOM THUMB */
.drange input[type=range]::-webkit-slider-thumb {
width: 20px; height: 20px;
border: 0; border-radius: 50%;
background: #be1e1e;
cursor: pointer;
}
.drange input[type=range]::-moz-range-thumb {
width: 20px; height: 20px;
border: 0; border-radius: 50%;
background: #be1e1e;
cursor: pointer;
}
/* (PART E) CUSTOM TRACK : FIRST SLIDER ONLY */
.drange input[type=range]:first-child::-webkit-slider-runnable-track {
background: #3e3e3e
}
.drange input[type=range]:first-child::-moz-range-track {
background: #3e3e3e;
}
/* (PART F) TO "RESIZE" TRACK */
/* (20px - 6px) / 2 = 7 px */
.drange input[type=range]::-webkit-slider-runnable-track {
height: 6px;
}
.drange input[type=range]::-moz-range-track {
height: 6px;
}
.drange input[type=range]::-webkit-slider-thumb {
margin-top: -7px;
}
/* (PART G) MIN/MAX VALUE */
.drange .dmin, .drange .dmax {
position: absolute; bottom: -5px;
font-size: 14px; font-weight: 700;
}
.drange .dmin { left: 0; }
.drange .dmax { right: 0; }
- Customizing the thumb is easy.
- Use
::-webkit-slider-thumb
for Webkit-based browsers (Chrome, Edge, Opera). - Use
::-moz-range-thumb
for Firefox. - Just treat the thumb as a “normal
<div>
“. Set the dimensions, colors, etc…
- Use
- Customizing the track is not so straightforward.
- Use
::-webkit-slider-runnable-track
for Webkit-based browsers. - Use
::-moz-range-track
for Firefox. - The gist is to set the height and background color for the track, but there is a “funky bug” with Webkit.
- Firefox will automatically center the track, Webkit doesn’t. That is why we have to manually offset it with a negative margin.
- Lastly, only draw the track for the first slider (set the background color). If both are set, there will be an irritating horizontal bar across one of the thumbs.
- Use
PART 5) JAVASCRIPT – RESTRICT THE MIN/MAX
window.addEventListener("load", () => {
// (PART A) LOOP THROUGH DUAL RANGE SLIDERS
document.querySelectorAll(".drange").forEach(drange => {
// (PART B) GET RANGE PICKERS & VALUE DISPLAY
let ranges = drange.querySelectorAll("input[type=range]"),
dmin = drange.querySelector(".dmin"),
dmax = drange.querySelector(".dmax");
// (PART C) MIN CANNOT BE MORE THAN MAX
ranges[0].addEventListener("input", e => {
if (+ranges[0].value >= +ranges[1].value) {
ranges[0].value = +ranges[1].value - 1;
}
dmin.innerHTML = ranges[0].value;
});
// (PART D) MAX CANNOT BE LESS THAN MIN
ranges[1].addEventListener("input", e => {
if (+ranges[1].value <= +ranges[0].value) {
ranges[1].value = +ranges[0].value + 1;
}
dmax.innerHTML = ranges[1].value;
});
// (PART E) INIT VALUE DISPLAY
dmin.innerHTML = ranges[0].value;
dmax.innerHTML = ranges[1].value;
});
});
Lastly, we need a small Javascript snippet to control the slider. TLDR:
- The min value cannot be equal or greater than the max.
- The max value cannot be equal or lesser than the min.
- Update the value display when the thumb is being shifted around.
THE END – SMALL NOTES
That’s all for this tutorial and sharing. Before we end, here are a few common questions I foresee people asking:
- Users who are not on Chrome, Opera, Edge, Brave, Firefox may see a “broken slider”. Nothing you can do… Unless you rebuild an entire custom slider that does not use
::-webkit
and::-moz
. - How to get the values – Just some CSS selector magic.
<div class="drange" id="demo">
var val = document.querySelectorAll("#demo input[type=range]");
- That’s all.
val[0]
is the min, andval[1]
is the max.