Slider
registry/pouf/slider.tsx
import * as RSlider from '@radix-ui/react-slider'
interface SliderProps {
value: number[]
onChange: (value: number[]) => void
min?: number
max?: number
step?: number
disabled?: boolean
label?: string
}
export function Slider({ value, onChange, min = 0, max = 100, step = 1, disabled, label }: SliderProps) {
return (
<RSlider.Root
className={[
'pouf-slider relative flex items-center w-full h-7 [touch-action:none] select-none',
'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed',
].join(' ')}
value={value}
onValueChange={onChange}
min={min}
max={max}
step={step}
disabled={disabled}
>
<RSlider.Track className="pouf-slider__track relative flex-1 h-3.5 rounded-[999px] bg-bg cushion-field">
<RSlider.Range className="pouf-slider__range absolute h-full rounded-[999px] bg-purple [box-shadow:inset_0_-3px_0_rgba(0,0,0,0.1)]" />
</RSlider.Track>
{value.map((_, i) => (
<RSlider.Thumb key={i} className={[
/* Ties to the range it drags via the same purple ring — one
* control, not a bead and a separate knob. */
'pouf-slider__thumb block w-[22px] h-[22px] rounded-[50%] bg-surface border-none cursor-pointer',
'[box-shadow:inset_0_0_0_3px_var(--purple),inset_0_-2px_0_rgba(0,0,0,0.08),0_3px_6px_rgba(58,46,92,0.22)]',
'[transition:box-shadow_140ms_ease,transform_140ms_ease]',
'hover:[transform:scale(1.08)] active:[transform:scale(0.94)]',
'focus-visible:[outline:3px_solid_var(--ink)] focus-visible:outline-offset-[3px]',
'data-[disabled]:cursor-not-allowed',
].join(' ')} aria-label={label ? `${label} thumb ${i + 1}` : undefined} />
))}
</RSlider.Root>
)
}
- Interaction
- carousel
DependenciesBundle weight · light
- ui-primitives
- @radix-ui/react-slider