Did you ever faced with range inputs? They are really simple, right? You can pass min and max, perhaps step as you can see below.
<input type="range" min="100" max="200" step="10">
But what if you need to create custom styled range input? Here comes the pain.
⬇️ tldr; if you just want the code, scroll down.
So, the range input have three parts. And if you want to implement it for yourself, probably you will use the same three parts as <div>s with a plenty of JavaScript magic, mouse event handling and calculating the value out of relative sizes and positions.
Trackbar, Progressbar, Thumb.
There are a lot of articles in the wild about styling range inputs. Maybe the most comprehensive articles about this topic are from 2017.
- https://css-tricks.com/sliding-nightmare-understanding-range-input/
- https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/
So we have the three parts, let's start with Thumb. It's a simple button-like draggable thingie. Unfortunately we need to use different prefixes like in old times for browser compatibility.
input[type="range"]::-webkit-slider-thumb {
/* Styles for Chrome */
}
input[type="range"]::-moz-range-thumb {
/* Styles for Firefox */
}
input[type="range"]::-ms-thumb {
/* Styles for IE */
}
The following can be the Trackbar which is the range what Thumb can slide on. Here we have another three pseudo elements for browsers.
input[type="range"]::-webkit-slider-runnable-track {
/* Styles for Chrome */
}
input[type="range"]::-moz-range-track {
/* Styles for Firefox */
}
input[type="range"]::-ms-track {
/* Styles for IE */
}
Great, but can we create a Progressbar for it? Sure, let's see following:
input[type="range"]::-moz-range-progress {
/* Styles for Firefox */
}
input[type="range"]::-ms-fill-lower {
/* Styles for IE */
}
/* Styles for Chrome... ¯\_(ツ)_/¯ */
Yep, that's all folks, Chrome don't have styling for Progressbar. Although you can implement a moderately ugly workaround using CSS calc() function, which is well supported in modern browsers. Besides CSS you will need some JS magic. The sad news are, pseudo elements can't be reached from JavaScript, but you can set CSS variables with it. Let's see the magic. You need to change only WebKit related styles of Trackbar.
input[type="range"] {
--webkitProgressPercent: 0%;
}
input[type="range"]::-webkit-slider-runnable-track {
background-image: linear-gradient(
90deg,
#f2f2f2 var(--webkitProgressPercent),
#262626 var(--webkitProgressPercent)
);
}
Now you only need to attach the --webkitProgressPercent variable to Thumb's position. Here you will need to listen to some mouse events to achieve the native functionality. Rather I will attach here a working example which includes JS functionality as well.
PS, I didn't tested it in IE, only in Chrome and Firefox. I created a React component for this issue as well.
Now you are out of Range Input nightmare!😁
I hope this article was helpful for you, if you have a question or suggestion, let's discuss it in comments. And don't forget to like it. 🙏






I literally just created an account here to say thank you for this, I had to make a slight modification on RangeInput.jsx to get the different color on the left track to change but other than that, this worked like a charm