Tailwind CSS Range Slider
Use the slider component to pick a numeric value from a range by dragging a thumb along a track, like a volume level or a price cap. For showing progress rather than picking a value, use the progress bar.
<div class="field w-full max-w-sm">
<span class="field-title">Volume</span>
<p class="field-description">
Set the playback volume (
<span
class="font-medium tabular-nums"
data-sp-slider-value="slider-demo-volume"
>
75
</span>
%).
</p>
<input
type="range"
class="slider mt-2"
id="slider-demo-volume"
max="100"
step="1"
value="75"
style="--val: 75%"
aria-label="Volume"
/>
</div>Usage
Add the slider class to an <input type="range">. The filled part of the track follows the value. Set the inline --val to match the initial value so the fill paints before JavaScript loads.
<input
type="range"
class="slider"
min="0"
max="100"
value="50"
style="--val: 50%"
/>Examples
Range slider
Overlay two sliders in a slider-range to pick a range with two thumbs. The wrapper paints the shared fill and keeps the thumbs from crossing.
Multiple thumbs
The wrapper takes any number of sliders, and each thumb is clamped between its neighbors.
<div class="slider-range w-full max-w-sm" style="--val-min: 10%; --val-max: 70%">
<input
type="range"
class="slider"
max="100"
step="10"
value="10"
aria-label="First value"
/>
<input
type="range"
class="slider"
max="100"
step="10"
value="20"
aria-label="Second value"
/>
<input
type="range"
class="slider"
max="100"
step="10"
value="70"
aria-label="Third value"
/>
</div>Vertical slider
Add slider-vertical for a bottom-to-top slider.
<div class="flex w-full max-w-sm items-center justify-center gap-6">
<input
type="range"
class="slider slider-vertical"
max="100"
step="1"
value="50"
style="--val: 50%"
aria-label="Value"
/>
<input
type="range"
class="slider slider-vertical"
max="100"
step="1"
value="25"
style="--val: 25%"
aria-label="Value"
/>
</div>Showing the value
Point an element at the slider with data-sp-slider-value and it mirrors the value automatically.
<div class="grid w-full max-w-sm gap-3">
<div class="flex items-center justify-between gap-2">
<label class="label" for="slider-temperature">Temperature</label>
<span
class="text-sm text-muted-foreground tabular-nums"
data-sp-slider-value="slider-temperature"
>
0.3
</span>
</div>
<input
type="range"
class="slider"
id="slider-temperature"
min="0"
max="1"
step="0.1"
value="0.3"
style="--val: 30%"
/>
</div>Slider in a field
Wrap the slider in a field with a title and description.
<div class="field w-full max-w-sm">
<span class="field-title">Price Range</span>
<p class="field-description">
Set your budget range ($
<span
class="font-medium tabular-nums"
data-sp-slider-value="slider-price-min"
>
200
</span>
-
<span
class="font-medium tabular-nums"
data-sp-slider-value="slider-price-max"
>
800
</span>
).
</p>
<div class="slider-range mt-2" style="--val-min: 20%; --val-max: 80%">
<input
type="range"
class="slider"
id="slider-price-min"
max="1000"
step="10"
value="200"
aria-label="Minimum price"
/>
<input
type="range"
class="slider"
id="slider-price-max"
max="1000"
step="10"
value="800"
aria-label="Maximum price"
/>
</div>
</div>Slider steps
Use step to snap the value to increments.
<div class="field w-full max-w-sm">
<span class="field-title">Zoom</span>
<p class="field-description">
Snaps in steps of 25 (
<span
class="font-medium tabular-nums"
data-sp-slider-value="slider-steps-zoom"
>
50
</span>
%).
</p>
<input
type="range"
class="slider mt-2"
id="slider-steps-zoom"
min="0"
max="100"
step="25"
value="50"
style="--val: 50%"
aria-label="Zoom"
/>
</div>Disabled
Add disabled and the slider mutes itself and blocks interaction.
RTL
Add dir="rtl" to any parent element, typically <html>, to render right-to-left. See the RTL guide for details.
<div id="slider-rtl-demo" dir="rtl" class="w-full max-w-sm">
<input
type="range"
class="slider mx-auto w-full max-w-xs"
max="100"
step="1"
value="75"
style="--val: 75%"
aria-label="Value"
/>
</div>
<script>
const translations = {
ar: { dir: "rtl" },
he: { dir: "rtl" },
en: { dir: "ltr" },
};
window.addEventListener("message", (e) => {
const t = translations[e.data?.lang];
if (e.data?.type !== "sp-language" || !t) return;
document.getElementById("slider-rtl-demo").dir = t.dir;
document.querySelectorAll("[data-i18n]").forEach((el) => {
el.textContent = t[el.dataset.i18n];
});
});
</script>JavaScript
Events
The slider is a native input, so listen to the native events: input fires on every change while dragging, change once the value settles.
slider.addEventListener("input", (e) => {
console.log(e.target.value);
});Methods
The fill updates on init and on user input. After changing value, min, or max programmatically, refresh with update():
const slider = document.querySelector("#volume");
slider.value = "90";
sp.slider(slider).update();