Slider
An input where the user selects a value from within a given range. Built with Base UI and Tailwind CSS. Copy-paste ready.
import { Slider } from "@/components/ui/slider";
export default function Particle() {
return <Slider defaultValue={50} />;
}
Installation
pnpm dlx shadcn@latest add @coss/slider
Usage
import { Slider, SliderValue } from "@/components/ui/slider"<Slider />API Reference
Slider
Root component. Styled wrapper for Slider.Root from Base UI with default min/max values and edge-aligned thumbs.
| Prop | Type | Default | Description |
|---|---|---|---|
min | number | 0 | Minimum value of the slider |
max | number | 100 | Maximum value of the slider |
Note: The component sets thumbAlignment="edge" by default, which aligns thumbs to the edge of the track rather than centering them.
SliderValue
Displays the current value. Styled wrapper for Slider.Value from Base UI.
Examples
For accessible labelling and validation, prefer using the Field component to wrap checkboxes. See the related example: Slider field.
With Label and Value
Pairs a visible label with a SliderValue that updates live as the thumb is dragged.
import { Field, FieldLabel } from "@/components/ui/field";
import { Slider, SliderValue } from "@/components/ui/slider";
export default function Particle() {
return (
<Field>
<Slider defaultValue={50}>
<div className="mb-2 flex items-center justify-between gap-1">
<FieldLabel className="font-medium text-sm">Opacity</FieldLabel>
<SliderValue />
</div>
</Slider>
</Field>
);
}
Disabled
Renders the slider at reduced opacity with interaction blocked — the current value is still visible.
import { Slider } from "@/components/ui/slider";
export default function Particle() {
return <Slider defaultValue={50} disabled />;
}
With Reference Labels
Displays min, max, and optional midpoint labels below the track to give users positional context without reading the exact value.
import { Slider } from "@/components/ui/slider";
export default function Particle() {
return (
<div>
<Slider
aria-label="Storage size in GB"
defaultValue={15}
max={35}
min={5}
/>
<div
aria-label="Storage size reference values"
className="mt-4 flex w-full items-center justify-between gap-1 font-medium text-muted-foreground text-xs"
role="group"
>
<span>5 GB</span>
<span>20 GB</span>
<span>35 GB</span>
</div>
</div>
);
}
With Tick Marks
Renders discrete tick marks along the track that correspond to valid step positions, guiding snapping behavior.
import { cn } from "@/lib/utils";
import { Slider } from "@/components/ui/slider";
const max = 12;
const skipInterval = 2;
const ticks = [...Array(max + 1)].map((_, i) => i);
export default function Particle() {
return (
<div>
<Slider aria-label="Value selector" defaultValue={5} max={max} />
<div
aria-label="Value scale from 0 to 12"
className="mt-3 flex w-full items-center justify-between gap-1 px-2.5 font-medium text-muted-foreground text-xs"
role="group"
>
{ticks.map((_, i) => (
<span
className="flex w-0 flex-col items-center justify-center gap-2"
key={String(i)}
>
<span
className={cn(
"h-1 w-px bg-muted-foreground/72",
i % skipInterval !== 0 && "h-0.5",
)}
/>
<span className={cn(i % skipInterval !== 0 && "opacity-0")}>
{i}
</span>
</span>
))}
</div>
</div>
);
}
Tooltip Indicator
A tooltip appears above the thumb as the user drags, displaying the exact current value and dismissing when the thumb is released.
"use client";
import { useState } from "react";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
export function Pattern() {
const [value, setValue] = useState(50);
const min = 0;
const max = 100;
const percentage = ((value - min) / (max - min)) * 100;
return (
<div className="mx-auto grid w-full max-w-sm gap-4">
<Label className="font-medium text-sm">Volume</Label>
<div className="relative pt-7">
<div
className="absolute top-0 rounded bg-foreground px-2 py-0.5 font-semibold text-background text-xs tabular-nums"
style={{
left: `${percentage}%`,
transform: "translateX(-50%)",
}}
>
{value}%
<div className="absolute -bottom-1 left-1/2 size-2 -translate-x-1/2 rotate-45 bg-foreground" />
</div>
<Slider
max={max}
min={min}
onValueChange={(val) =>
setValue(Array.isArray(val) ? (val[0] ?? 50) : val)
}
step={1}
value={[value]}
/>
</div>
</div>
);
}
Rating With Emoji
A 1–5 rating slider where the emoji and label below change to reflect the selected sentiment as the thumb moves.
"use client";
import { useState } from "react";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
const emojis = ["😡", "🙁", "😐", "🙂", "😍"];
const labels = ["Awful", "Poor", "Okay", "Good", "Amazing"];
export function Pattern() {
const [value, setValue] = useState(3);
return (
<div className="mx-auto grid w-full max-w-sm gap-3">
<Label className="font-medium text-sm">Rate your experience</Label>
<div className="flex items-center gap-3">
<Slider
max={5}
min={1}
onValueChange={(val) =>
setValue(Array.isArray(val) ? (val[0] ?? 3) : val)
}
step={1}
value={[value]}
/>
<span aria-hidden="true" className="text-2xl">
{emojis[value - 1]}
</span>
</div>
<span className="text-center font-medium text-muted-foreground text-xs">
{labels[value - 1]}
</span>
</div>
);
}
Volume Control
A media-player-style volume slider with a muted/low/high icon that updates as the level changes. Clicking the icon toggles mute on and off.
"use client";
import { Volume1Icon, Volume2Icon, VolumeXIcon } from "lucide-react";
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
export default function Particle() {
const [volume, setVolume] = useState(60);
const Icon =
volume === 0 ? VolumeXIcon : volume < 50 ? Volume1Icon : Volume2Icon;
return (
<div className="flex w-full max-w-sm items-center gap-3">
<button
aria-label={volume === 0 ? "Unmute" : "Mute"}
className="text-muted-foreground transition-colors hover:text-foreground"
onClick={() => setVolume(volume === 0 ? 60 : 0)}
type="button"
>
<Icon aria-hidden="true" className="size-5" />
</button>
<Slider
aria-label="Volume"
className="flex-1"
max={100}
min={0}
onValueChange={(v) => setVolume(Array.isArray(v) ? (v[0] ?? 60) : v)}
value={[volume]}
/>
<span className="w-8 text-right text-muted-foreground text-sm tabular-nums">
{volume}
</span>
</div>
);
}
Price Range
A dual-thumb slider that lets users set a minimum and maximum price. The selected range is shown above the track and updates live as either thumb is dragged.
Price Range
$200 – $800"use client";
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
export default function Particle() {
const [range, setRange] = useState([200, 800]);
return (
<div className="w-full max-w-sm space-y-4 rounded-xl border p-5">
<div className="flex items-center justify-between">
<p className="font-medium text-sm">Price Range</p>
<span className="font-semibold text-sm tabular-nums">
${range[0]} – ${range[1]}
</span>
</div>
<Slider
aria-label="Price range"
max={1000}
min={0}
onValueChange={(v) => setRange(Array.isArray(v) ? [...v] : [v])}
step={10}
value={range}
/>
<div className="flex justify-between text-muted-foreground text-xs">
<span>$0</span>
<span>$1,000</span>
</div>
</div>
);
}
Hue Color Picker
A full-spectrum hue slider with a gradient track. A color swatch previews the selected hsl() value and updates in real time as the thumb moves.
Accent Color
hsl(210, 70%, 55%)
"use client";
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
export default function Particle() {
const [hue, setHue] = useState(210);
return (
<div className="w-full max-w-sm space-y-4 rounded-xl border p-5">
<div className="flex items-center justify-between">
<p className="font-medium text-sm">Accent Color</p>
<div
className="size-6 rounded-full border"
style={{ backgroundColor: `hsl(${hue}, 70%, 55%)` }}
/>
</div>
<div
className="h-2 rounded-full"
style={{
background:
"linear-gradient(to right, hsl(0,70%,55%), hsl(60,70%,55%), hsl(120,70%,55%), hsl(180,70%,55%), hsl(240,70%,55%), hsl(300,70%,55%), hsl(360,70%,55%))",
}}
/>
<Slider
aria-label="Color hue"
max={360}
min={0}
onValueChange={(v) => setHue(Array.isArray(v) ? (v[0] ?? 210) : v)}
value={[hue]}
/>
<p className="text-center text-muted-foreground text-xs">
hsl({hue}, 70%, 55%)
</p>
</div>
);
}
Temperature Control
A room-temperature slider that colors the label green, blue, or orange to reflect the comfort level, with a text hint that updates as the value changes.
Room Temperature
22°C"use client";
import { ThermometerIcon } from "lucide-react";
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
export default function Particle() {
const [temp, setTemp] = useState(22);
const color =
temp <= 18
? "text-blue-500"
: temp <= 24
? "text-green-500"
: "text-orange-500";
const label =
temp <= 18 ? "Too cold" : temp <= 24 ? "Comfortable" : "Too warm";
return (
<div className="w-full max-w-sm space-y-4 rounded-xl border p-5">
<div className="flex items-center gap-2">
<ThermometerIcon aria-hidden="true" className={`size-5 ${color}`} />
<p className="font-medium text-sm">Room Temperature</p>
<span className={`ml-auto font-semibold tabular-nums ${color}`}>
{temp}°C
</span>
</div>
<Slider
aria-label="Temperature"
max={30}
min={10}
onValueChange={(v) => setTemp(Array.isArray(v) ? (v[0] ?? 22) : v)}
step={1}
value={[temp]}
/>
<div className="flex justify-between text-muted-foreground text-xs">
<span>10°C</span>
<span className="font-medium text-foreground">{label}</span>
<span>30°C</span>
</div>
</div>
);
}
Display Settings
Three sliders — brightness, contrast, and saturation — each displaying a live SliderValue. A Reset button restores all three to their defaults.
Display Settings
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Slider, SliderValue } from "@/components/ui/slider";
const settings = [
{ key: "brightness", label: "Brightness" },
{ key: "contrast", label: "Contrast" },
{ key: "saturation", label: "Saturation" },
] as const;
const defaults = { brightness: 80, contrast: 50, saturation: 60 };
export default function Particle() {
const [values, setValues] = useState(defaults);
return (
<div className="w-full max-w-sm space-y-5 rounded-xl border p-5">
<p className="font-semibold">Display Settings</p>
{settings.map(({ key, label }) => (
<Slider
key={key}
max={100}
min={0}
onValueChange={(v) =>
setValues((prev) => ({
...prev,
[key]: Array.isArray(v) ? (v[0] ?? 0) : v,
}))
}
value={[values[key]]}
>
<div className="mb-2 flex items-center justify-between text-sm">
<span className="text-muted-foreground">{label}</span>
<SliderValue />
</div>
</Slider>
))}
<div className="flex gap-2 pt-1">
<Button
className="flex-1"
onClick={() => setValues(defaults)}
variant="outline"
>
Reset
</Button>
<Button className="flex-1">Apply</Button>
</div>
</div>
);
}

