Shadcn Slider for React and Tailwind
A slider for selecting a value from a range.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/slider.jsonpnpm dlx shadcn@latest add https://kit.dev/r/slider.jsonnpx shadcn@latest add https://kit.dev/r/slider.jsonyarn shadcn@latest add https://kit.dev/r/slider.json<Step>This component depends on Field. Install it first if you haven't already.</Step>
Install the following dependencies:
bun add @ark-ui/reactpnpm add @ark-ui/reactnpm install @ark-ui/reactyarn add @ark-ui/reactCopy and paste the following code into your project.
"use client";
import { Slider as ArkSlider, useSliderContext } from "@ark-ui/react/slider";
import React from "react";
import { cn } from "@/lib/utils";
import { FieldLabel } from "@/components/ui/field";
export const useSlider = useSliderContext;
interface SliderProps extends React.ComponentProps<typeof ArkSlider.Root> {
/**
* The interval between markers.
*
* @default 1
*/
markerInterval?: number;
/**
* The labels to show on the markers.
*
* @default []
*/
markerLabels?: string[];
/**
* Whether to show markers.
*
* @default false
*/
showMarkers?: boolean;
}
export const Slider = (props: SliderProps) => {
const {
value,
defaultValue,
min = 0,
max = 100,
markerInterval = 1,
showMarkers = false,
markerLabels = [],
tabIndex,
className,
children,
...rest
} = props;
const _values = React.useMemo(() => {
if (Array.isArray(value)) {
return value;
}
if (Array.isArray(defaultValue)) {
return defaultValue;
}
return [min, max];
}, [value, defaultValue, min, max]);
return (
<ArkSlider.Root
className={cn(
"flex flex-col gap-3",
"data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:h-full",
className
)}
data-slot="slider"
defaultValue={defaultValue}
max={max}
min={min}
value={value}
{...rest}
>
{children}
<ArkSlider.Control
className={cn(
"relative",
"w-full",
"flex items-center",
"touch-none select-none",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
"data-disabled:pointer-events-none data-disabled:opacity-64"
)}
data-slot="slider-control"
>
<ArkSlider.Track
className={cn(
"grow",
"bg-input/64",
"rounded-full",
"select-none overflow-hidden",
"data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2"
)}
data-slot="slider-track"
>
<ArkSlider.Range
className={cn(
"absolute",
"bg-primary",
"select-none",
"data-[orientation=horizontal]:h-full",
'data-[orientation=vertical]:w-full data-[orientation=vertical]:not-[[class^="h-"]]:not-[[class*="_h-"]]:self-stretch'
)}
data-slot="slider-range"
/>
</ArkSlider.Track>
{Array.from({ length: _values.length }, (_, index) => {
const key = `slider-thumb-${index}`;
return (
<ArkSlider.Thumb
className={cn(
"relative",
"shrink-0",
"size-4.5",
"bg-white",
"rounded-full border border-input shadow-xs/5",
"cursor-grab select-none",
"transition-[color,box-shadow,transform]",
"focus-visible:border-primary focus-visible:outline-hidden focus-visible:ring-[3px] focus-visible:ring-ring/32",
"origin-left data-dragging:scale-110 data-dragging:cursor-grabbing data-dragging:border-primary data-dragging:ring-[3px] data-dragging:ring-ring/32",
"pointer-coarse:after:absolute pointer-coarse:after:h-full pointer-coarse:after:min-h-11",
"motion-reduce:transition-none!"
)}
data-slot="slider-thumb"
index={index}
key={key}
tabIndex={tabIndex ?? undefined}
>
<ArkSlider.HiddenInput />
</ArkSlider.Thumb>
);
})}
</ArkSlider.Control>
{showMarkers && (
<ArkSlider.MarkerGroup
className={cn(
"w-full",
"flex items-center justify-between gap-1",
"mt-3 px-2.5",
"font-medium text-muted-foreground text-xs",
"data-[orientation=vertical]:hidden",
"pointer-events-none"
)}
>
{Array.from({ length: max + 1 }, (_, index) => (
<ArkSlider.Marker
className={cn(
"group/marker",
"flex w-0 flex-col items-center justify-center gap-2",
"data-[state=at-value]:text-foreground data-[state=under-value]:text-foreground"
)}
data-interval={index % markerInterval === 0 ? undefined : ""}
data-slot="slider-marker"
key={String(index)}
value={index}
>
<span
className={cn(
"h-1 w-px",
"bg-muted-foreground/70 group-data-[state=at-value]/marker:bg-foreground group-data-[state=under-value]/marker:bg-foreground",
"group-data-interval/marker:h-0.5"
)}
/>
<span className={cn("group-data-interval/marker:opacity-0")}>
{markerLabels?.[index] ?? index}
</span>
</ArkSlider.Marker>
))}
</ArkSlider.MarkerGroup>
)}
</ArkSlider.Root>
);
};
export const SliderLabel = (props: React.ComponentProps<typeof FieldLabel>) => {
const { children, ...rest } = props;
return (
<FieldLabel {...rest}>
<ArkSlider.Label data-slot="slider-label">{children}</ArkSlider.Label>
</FieldLabel>
);
};
export const SliderValue = (
props: React.ComponentProps<typeof ArkSlider.ValueText>
) => {
const { className, ...rest } = props;
return (
<FieldLabel asChild>
<ArkSlider.ValueText
className={cn("ms-auto tabular-nums", className)}
data-slot="progress-value"
{...rest}
/>
</FieldLabel>
);
};Update the import paths to match your project setup.
Usage
import { Slider } from "@/components/ui/slider";<Slider />Controlled
Control the value with value and onValueChange for a controlled slider.
Examples
With label and value
Use <Field>, <SliderLabel>, and <SliderValue> for accessible labelling and to show the current value.
Range
Use an array with two values for a range slider.
Vertical
Use orientation="vertical" for a vertical slider.
Disabled
Use the disabled prop to disable the slider.
Min and max
Set min and max to constrain the slider's value range.
Marks
The showMarkers and markerInterval props display markers and control the interval between them.
Step
Set step to control the slider's granularity.
Use with showMarkers and markerLabels to show custom labels on the markers.
Marks are only supported for horizontal sliders.
API Reference
Slider
Root component. Manages value, track, range, and thumb(s).
| Prop | Type | Default |
|---|---|---|
value | number[] | - |
defaultValue | number[] | - |
onValueChange | (details: ValueChangeDetails) => void | - |
min | number | 0 |
max | number | 100 |
step | number | 1 |
orientation | "horizontal" | "vertical" | "horizontal" |
disabled | boolean | false |
showMarkers | boolean | false |
markerInterval | number | 1 |
markerLabels | string[] | [] |
className | string | - |
SliderLabel
Label for the slider. Required for accessibility.
| Prop | Type | Default |
|---|---|---|
className | string | - |
SliderValue
Shows the current value. Useful for numeric display or formatting.
| Prop | Type | Default |
|---|---|---|
className | string | - |
For a complete list of props, see the Ark UI documentation.