Styling Range Sliders
<input type="range"> renders a thumb (the draggable handle) sitting on a track (the line it slides along). There is no single, universally supported way to style either part yet — each browser engine exposes its own vendor-prefixed pseudo-elements, so a slider that looks intentional across Chrome, Firefox, and Safari needs several parallel rule sets.
Warning
Range slider styling is one of the last corners of CSS without a unified standard pseudo-element. You must write separate, vendor-prefixed rules per engine —
::-webkit-slider-thumb and ::-webkit-slider-runnable-track for Chromium/Safari, ::-moz-range-thumb and ::-moz-range-track for Firefox. Skipping one engine means the slider falls back to that browser's default look, which can look inconsistent next to your custom styling.Styling the track
CSS
input[type="range"] {
-webkit-appearance: none; /* required to unlock custom track/thumb styling in WebKit/Blink */
appearance: none;
width: 100%;
background: transparent;
}
/* Chromium & Safari */
input[type="range"]::-webkit-slider-runnable-track {
height: 6px;
border-radius: 3px;
background: #d9d9d9;
}
/* Firefox */
input[type="range"]::-moz-range-track {
height: 6px;
border-radius: 3px;
background: #d9d9d9;
}Styling the thumb
CSS
/* Chromium & Safari */
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
margin-top: -7px; /* vertically centers thumb on a 6px track */
border-radius: 50%;
background: #2a6df4;
border: 2px solid white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
cursor: pointer;
}
/* Firefox */
input[type="range"]::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #2a6df4;
border: 2px solid white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
cursor: pointer;
}Worked example: a complete custom slider
CSS
<input type="range" class="slider" min="0" max="100" value="40" />
.slider {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 6px;
border-radius: 3px;
background: linear-gradient(to right, #2a6df4 0%, #2a6df4 40%, #d9d9d9 40%, #d9d9d9 100%);
outline-offset: 4px; /* keep the focus ring visible and clear of the track */
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 22px;
height: 22px;
border-radius: 50%;
background: white;
border: 3px solid #2a6df4;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
cursor: pointer;
transition: transform 0.15s ease;
}
.slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
.slider::-moz-range-track {
height: 6px;
border-radius: 3px;
background: #d9d9d9;
}
.slider::-moz-range-thumb {
width: 22px;
height: 22px;
border-radius: 50%;
background: white;
border: 3px solid #2a6df4;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
cursor: pointer;
}
/* Always keep a visible focus indicator for keyboard users */
.slider:focus-visible::-webkit-slider-thumb {
outline: 2px solid #2a6df4;
outline-offset: 2px;
}The simpler option: accent-color
If all you need is to recolor a range input to match your brand — without building fully custom thumb and track shapes — the accent-color property does that in a single declaration, and it works across checkboxes, radios, and progress bars too, not just sliders.
CSS
input[type="range"] {
accent-color: #2a6df4;
/* Recolors the filled track and thumb using the browser's native
rendering — no vendor prefixes, no pseudo-elements, no thumb-size
math required. */
}Note
`accent-color` is the pragmatic choice when you just want the slider to feel "on brand" rather than fully redesigned. It's a single, unprefixed, well-supported property — reach for the vendor-prefixed pseudo-element approach above only when you need a genuinely custom thumb shape, track gradient, or size that accent-color can't express.
Next
See how far the same idea goes on checkboxes and radios with accent-color, or continue exploring form styling with [appearance property](/css/appearance-property) and [Form Validation Styles](/css/form-validation-styles).