Published on: Updated on: Time to read: 1 mins
development coding javascript ui

Styled Range Input - A way out of Range Input nightmare

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.

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.

I created a React component for this issue as well.

PS, I didn't tested it in IE, only in Chrome and Firefox.

Now you are out of Range Input nightmare!😁