UX experience: Customize range input like Apple IOS slider

May 15, 2023


One day I found out that Apple IOS has a very beautiful slider and it inspired me to build a similar input range slider with HTML. After a few hours of try and errors, I finally built one. Here is the result.

Customize range input like Apple IOS native slider


  • thumb: The draggable part of the slider
  • track: The bar that the thumb slides along
  • progress track: The part of the track that is filled with color

Lessons learned

OnMouceUp/OnMouseDown vs OnMouseEnter/OnMouseLeave

Initially, I used onmouseenter and onmouseleave to control the color of the progressed track, but because the track height is small, once the user’s cursor leaves the input, the color will change which results in a flickering effect. So I changed to onmousedown and onmouseup to control the color of the progressed track.

Wipe out the default style

Different browsers have different default styles for the input range. To make the slider looks consistent across all browsers, we need to wipe out the default style. 1

/* Remove the basic style */
input[type="range"] {
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
	background: none;
	outline: none;

/* Remove the track style */
/* Chrome, Safari, Opera, and Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
	height: 0.3rem;
	opacity: 60%;

/* Firefox */
input[type="range"]::-moz-range-track {
	height: 0.5rem;
	opacity: 60%;

But the caveat is that you can’t remove the appearance of the thumb or the interaction will break. So we need to set the thumb to transparent.

/* Chrome, Safari, Opera, and Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
	opacity: 0;

/* Firefox */
input[type="range"]::-moz-range-thumb {
	opacity: 0;

How to color progress track

There are multiple ways to accomplish this.

  • Use linear-gradient to create a gradient background
  • Use box-shadow to create a shadow from the thumb and hide the overflow box-shadow 2

I think the second method is not reliable, especially since we want to achieve a transparent thumb experience. So I used the first method.

input[type="range"] {
	background-image: linear-gradient(to right, #ff0000 0%, #ff0000 50%, #ffffff 50%, #ffffff 100%);

The first and the second color is the color of progressed track and the third and the fourth color is the color of the rest of the track. You need to calculate the percentage of the progressed track.

Be careful of the min and max when calculating the percentage.

		"background-image": `linear-gradient(to right, 
		${progressTrackColor()} 0%, ${progressTrackColor()} 
		${((sliderValue() - min) / (max - min)) * 100}%, ${trackColor}
		${((sliderValue() - min) / (max - min)) * 100}%, ${trackColor} 100%)`,

How to accomplish the hover and mouseleave using different animation

In short, we can set the default transition for non-hover events and override the transition for hover events.

input[type="range"] {
	transition: transform 0.6s ease-in-out;

    We use this to override the default transition to accomplish
    different animation between mouseenter and mouseleave
	&:hover {
		transform: scaleY(1.75);
		transition: transform 0.15s ease-out;

Left for future experiment

Overall the range works great on the desktop but the experience is terrible on the mobile. When you click the range bar it can’t smoothly focus on the thumb and move with your touch moves. At first glance the package range-touch looks promising. But I would like to find a more lightweight solution without importing another package


  1. Creating A Custom Range Input That Looks Consistent Across All Browsers

  2. How to style HTML5 range input to have different color before and after slider?