Slider
An input for selecting a value within a range.
Basic Usage
import { Slider } from "@repo/ui/components/slider";
/* BASIC USAGE EXAMPLE */
export const Example1 = () => {
return <Slider defaultValue={[50]} />;
};
Controlled
Value: 30
"use client";
import { useState } from "react";
import { Slider } from "@repo/ui/components/slider";
/* CONTROLLED SLIDER EXAMPLE */
export const Example2 = () => {
const [value, setValue] = useState([30]);
return (
<div className="w-full max-w-xs space-y-4">
<Slider value={value} onChange={(v) => setValue(v as number[])} />
<p className="text-muted-foreground text-center text-sm">
Value:{" "}
<span className="text-foreground font-medium">{value[0]}</span>
</p>
</div>
);
};
Range Slider
Range: 25 – 75
"use client";
import { useState } from "react";
import { Slider } from "@repo/ui/components/slider";
/* RANGE SLIDER EXAMPLE */
export const Example3 = () => {
const [value, setValue] = useState([25, 75]);
return (
<div className="w-full max-w-xs space-y-4">
<Slider value={value} onChange={(v) => setValue(v as number[])} />
<p className="text-muted-foreground text-center text-sm">
Range:{" "}
<span className="text-foreground font-medium">{value[0]}</span>
{" – "}
<span className="text-foreground font-medium">{value[1]}</span>
</p>
</div>
);
};
Disabled
import { Slider } from "@repo/ui/components/slider";
/* DISABLED SLIDER EXAMPLE */
export const Example4 = () => {
return (
<div className="w-full max-w-xs space-y-4">
<Slider defaultValue={[50]} isDisabled />
</div>
);
};
With Labels
75%
50%
"use client";
import { useState } from "react";
import { Slider } from "@repo/ui/components/slider";
import { Label } from "@repo/ui/components/label";
/* SLIDER WITH STEP AND CUSTOM RANGE */
export const Example5 = () => {
const [volume, setVolume] = useState([75]);
const [brightness, setBrightness] = useState([50]);
return (
<div className="w-full max-w-xs space-y-6">
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label>Volume</Label>
<span className="text-muted-foreground text-sm">
{volume[0]}%
</span>
</div>
<Slider
value={volume}
onChange={(v) => setVolume(v as number[])}
minValue={0}
maxValue={100}
step={5}
/>
</div>
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label>Brightness</Label>
<span className="text-muted-foreground text-sm">
{brightness[0]}%
</span>
</div>
<Slider
value={brightness}
onChange={(v) => setBrightness(v as number[])}
minValue={0}
maxValue={100}
step={10}
/>
</div>
</div>
);
};
Component Code
"use client";
import {
Slider as AriaSlider,
SliderProps as AriaSliderProps,
SliderThumb,
SliderTrack,
} from "react-aria-components";
import { cn } from "tailwind-variants";
export interface SliderProps<T> extends AriaSliderProps<T> {
label?: string;
thumbLabels?: string[];
}
export function Slider<T extends number | number[]>({
thumbLabels,
className,
...props
}: SliderProps<T>) {
return (
<AriaSlider
data-slot="slider"
{...props}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
>
{/* SliderTrack is a tall container for the thumb to move in */}
<SliderTrack
data-slot="slider-track"
className="relative h-5 w-full"
>
{({ state }) => (
<>
{/* Visible track bar - centered vertically */}
<div className="bg-muted absolute top-1/2 h-1.5 w-full -translate-y-1/2 rounded-full" />
{/* Fill bar - centered vertically */}
{state.values.length === 1 ? (
// Single thumb - fill from start to thumb
<div
className="bg-primary absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full"
style={{
width: `${state.getThumbPercent(0) * 100}%`,
}}
/>
) : state.values.length === 2 ? (
// Range slider - fill between the two thumbs
<div
className="bg-primary absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full"
style={{
left: `${state.getThumbPercent(0) * 100}%`,
width: `${(state.getThumbPercent(1) - state.getThumbPercent(0)) * 100}%`,
}}
/>
) : null}
{/* Thumbs - React Aria sets left position, we need to center vertically */}
{state.values.map((_, i) => (
<SliderThumb
key={i}
index={i}
aria-label={thumbLabels?.[i]}
className="border-primary bg-background ring-ring/50 absolute top-1/2 block size-4 rounded-full border shadow transition-colors hover:ring-4 focus-visible:outline-none focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50"
/>
))}
</>
)}
</SliderTrack>
</AriaSlider>
);
}