Browse the docs
ComponentsNo. 51 of 109
Slider
Pick a number or a range by dragging or with the arrow keys, horizontal or vertical.
Installation
pnpm dlx shadcn@latest add @corsair-ui/sliderNo setup needed: the CLI finds @corsair-ui in the shadcn registry directory. The files land in your project as source: edit them like your own code. More in Installation.
- Also adds
- utils
- npm
@radix-ui/react-sliderclsxtailwind-merge
Examples
Default
40%
Range
Two thumbs, each with its own accessible name.
PriceR$ 200 – R$ 800
Vertical and disabled
API
| Prop | Type | Default |
|---|---|---|
thumbLabelsAn accessible name for each thumb, e.g. minimum and maximum price. | string[] | — |
Built on Radix Slider; every prop it takes is passed through.
Accessibility
- Arrow keys step, Page Up and Page Down jump, Home and End go to the ends.
- Each thumb is announced with its own value.
Compatibility
- Tailwind CSS
- 3.4 and 4, both checked in CI
- React
- 19
- Rendering
- Client component ("use client")
Source
1 file, installed as source you own
slider.tsxView on GitHub"use client";
import * as SliderPrimitive from "@radix-ui/react-slider";
import type { ComponentProps } from "react";
import { cn } from "@/registry/default/lib/utils";
interface SliderProps extends ComponentProps<typeof SliderPrimitive.Root> {
/**
* An accessible name for each thumb, e.g. `["Minimum price", "Maximum price"]`.
* With one thumb, `aria-label` / `aria-labelledby` on the slider are enough.
*/
thumbLabels?: string[];
}
/**
* Pick a number, or a range with two values, by dragging or with the arrow
* keys. The number of thumbs follows `value` / `defaultValue`.
*/
function Slider({
className,
defaultValue,
value,
min = 0,
max = 100,
thumbLabels,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
...props
}: SliderProps) {
const count = (value ?? defaultValue ?? [min]).length;
return (
<SliderPrimitive.Root
data-slot="slider"
defaultValue={defaultValue}
value={value}
min={min}
max={max}
className={cn(
"relative flex w-full cursor-pointer touch-none items-center select-none",
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
className
)}
{...props}
>
<SliderPrimitive.Track
data-slot="slider-track"
className="bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
>
<SliderPrimitive.Range
data-slot="slider-range"
className="bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
/>
</SliderPrimitive.Track>
{Array.from({ length: count }, (_, index) => (
<SliderPrimitive.Thumb
// Thumbs are positional (the first is the lower value), so the index is the identity.
key={index}
data-slot="slider-thumb"
aria-label={thumbLabels?.[index] ?? (count === 1 ? ariaLabel : undefined)}
aria-labelledby={thumbLabels?.[index] ? undefined : ariaLabelledBy}
className={cn(
"border-primary bg-background ring-ring/50 block size-4 shrink-0 cursor-grab rounded-full border shadow active:cursor-grabbing",
"transition-[color,box-shadow] outline-none motion-reduce:transition-none",
"hover:ring-4 focus-visible:ring-4",
"disabled:pointer-events-none disabled:opacity-50"
)}
/>
))}
</SliderPrimitive.Root>
);
}
export { Slider, type SliderProps };