Cross Browser Range Input Slider

April 19, 2022

Above is a demonstration of a basic customised cross browser range input slider. I put this together whilst developing UI elements for one of my projects.

Open Demo

You can also right-click on the link above and select ‘Save Link As…’ (or similar) to download the entire demo as a single html file.

There are lots of cross browser customised range input sliders out there, however I wanted two bits of key functionality that I didn’t find in any of the examples I came across:

  1. I wanted an additional hit / interactive area around the range slider track, without widening the visual element of the actual range slider track. This would allow me to have a relatively thin visual element for the range slider track whilst also having a more easily clickable/tappable area for making a selection by clicking on the range track (rather than dragging the range thumb). In this version you can make the visual of the slider track and the interactive area different widths, – whatever you want.
  2. I still wanted to include track highlighting to indicate the selected range in the track.

I arrived at a somewhat novel hack / solution that involved adding my own elements behind the actual slider for the slider tracks whilst leaving all the functionality in the native (but restyled) html range input element. Here is another example of this range slider included in the UI for a three.js project.

Here is an example of the HTML:


<div class="range-slider-container">
  <div class="range-track"></div>
  <div id="range-slider-1-track-highlight" class="range-track track-highlight"></div>
  <input type="range" min="0" max="100" value="100" class="slider" id="range_slider_1">
</div>

I then use some JavaScript to resize my custom slider tracks. Here is my complete Javascript code:


let range_slider_1 = document.getElementById("range_slider_1");
    
update_slider()
range_slider_1.addEventListener("input", function (e) {
  update_slider();
});

function update_slider() {
  let slider_value = range_slider_1.value/100;
  let slider_width = range_slider_1.offsetWidth;
  let range_slider_1_value = document.getElementById("range-slider-1-value");
  let range_slider_1_track_highlight = document.getElementById("range-slider-1-track-highlight");
  range_slider_1_track_highlight.style.width = slider_width * slider_value + "px";
  range_slider_1_value.innerHTML = slider_value;
}
window.addEventListener('resize', function(event) {
  update_slider()
}, true);

* Note that I am listening to the window resize to help make the slider responsive.

And here is the CSS:


.range-slider-container {
  position: relative;
  width: 220px;
  margin-top: 10px;
} 
input[type="range"] {
  -webkit-appearance: none;
  height: 10px;
  box-sizing: border-box;
  border:  1px dashed rgba(111,111,111,0.3); /* set opacity to 0 to hide */
  width: 100%;
  background:  0;
  cursor: pointer;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%; 
  box-sizing: border-box;
  box-shadow: -1px 1px 5px rgba(0,0,0,.4);
  border: 3px solid #ddd;
  background: #04AA6D; /*color*/
}
.slider::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  box-sizing: border-box;
  box-shadow: -1px 1px 5px rgba(0,0,0,.4); 
  border: 3px solid #ddd;
  background: #04AA6D; /*color*/
}
.range-track {
  width: 100%;
  height: 4px;
  background: #ccc; /*color*/
  position: absolute;
  pointer-events: none;
  top: 10px;
  left:  1px;
  border-radius: 3px;
}
.track-highlight {
  background: #04AA6D; /*color*/
}
#range_slider_1 {
  z-index: 500;
  position: absolute;
  left: 0;
  top: 5px;
}

Otherwise I hope this solution is useful to you and please keep me posted if you find any issues or improvements. 🙂

If you liked this resources please consider showing your appreciation and offering your support. It will make my day!

Buy me a coffee