Slider

Slider provides a drag-based numeric input for continuous or stepped values, built on Radix Slider primitives.

When to use

  • Let users adjust numeric settings with immediate visual feedback.
  • Select a bounded range (for example, minimum and maximum thresholds).
  • Replace text/number inputs when precision beyond the chosen step is not required.

Behavior notes

  • Pass one value ([n]) for a single-thumb slider, two values ([min, max]) for range selection.
  • Use value and onValueChange for controlled usage.
  • Configure bounds with min, max, and increments with step.

Example

const [value, setValue] = useState([35]);

<Slider
  value={value}
  onValueChange={setValue}
  min={0}
  max={100}
  step={1}
  aria-label='Volume'
/>;

Preview

Threshold

40%

Range

20 - 80

Usage

import React from 'react';

import { Text, Slider } from '@branditdev/ui';

export function SliderDemo() {
  const [singleValue, setSingleValue] = React.useState([40]);
  const [rangeValue, setRangeValue] = React.useState([20, 80]);

  return (
    <div className='w-full max-w-md space-y-5'>
      <div className='space-y-2'>
        <div className='flex items-center justify-between'>
          <Text variant='body-sm'>Threshold</Text>
          <Text variant='body-sm'>{singleValue[0]}%</Text>
        </div>
        <Slider
          value={singleValue}
          onValueChange={setSingleValue}
          min={0}
          max={100}
          step={1}
          aria-label='Threshold slider'
        />
      </div>

      <div className='space-y-2'>
        <div className='flex items-center justify-between'>
          <Text variant='body-sm'>Range</Text>
          <Text variant='body-sm'>
            {rangeValue[0]} - {rangeValue[1]}
          </Text>
        </div>
        <Slider
          value={rangeValue}
          onValueChange={setRangeValue}
          min={0}
          max={100}
          step={1}
          aria-label='Range slider'
        />
      </div>
    </div>
  );
}

API

Slider(props): Element

Defined in: components/slider/slider.tsx:13

Slider UI component.

Parameters

NameTypeOptionalDefaultDescription
propsSliderProps & RefAttributes<HTMLSpanElement>no-Component properties.

Returns

Element

Rendered component.

Source

import { Slider as SliderPrimitive } from 'radix-ui';
import React from 'react';

import { cn } from '@branditdev/ui';

export function Slider({
  className,
  defaultValue,
  value,
  min = 0,
  max = 100,
  ...props
}: React.ComponentProps<typeof SliderPrimitive.Root>) {
  const _values = React.useMemo(
    () =>
      Array.isArray(value)
        ? value
        : Array.isArray(defaultValue)
          ? defaultValue
          : [min, max],
    [value, defaultValue, min, max]
  );

  return (
    <SliderPrimitive.Root
      data-slot='slider'
      defaultValue={defaultValue}
      value={value}
      min={min}
      max={max}
      className={cn(
        'relative flex w-full touch-none items-center select-none 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={cn(
          'relative grow overflow-hidden rounded-full bg-muted 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={cn(
            'absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full'
          )}
        />
      </SliderPrimitive.Track>
      {Array.from({ length: _values.length }, (_, index) => (
        <SliderPrimitive.Thumb
          data-slot='slider-thumb'
          key={index}
          className='block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50'
        />
      ))}
    </SliderPrimitive.Root>
  );
}