Slider

Numeric range input with immediate feedback for tuning values like volume, thresholds, and preference intensity.

AccessibleDark ModeKeyboard Nav

Install

$npx react-principles add slider
01

Live Demo

Explore all variants and interactive states in Storybook.

Open Storybookopen_in_new
40

Current value: 40

02

Code Snippet

src/ui/Slider.tsx
import { Slider } from "@/ui/Slider";

<Slider
  label="Volume"
  value={volume}
  min={0}
  max={100}
  step={1}
  onValueChange={setVolume}
/>
03

Copy-Paste (Single File)

Slider.tsx
import { useState } from "react";
import { cn } from "@/lib/utils";

export interface SliderProps {
  value?: number;
  defaultValue?: number;
  min?: number;
  max?: number;
  step?: number;
  onValueChange?: (value: number) => void;
  label?: string;
  showValue?: boolean;
  className?: string;
}

export function Slider({
  value,
  defaultValue = 50,
  min = 0,
  max = 100,
  step = 1,
  onValueChange,
  label,
  showValue = true,
  className,
}: SliderProps) {
  const [internalValue, setInternalValue] = useState(defaultValue);
  const isControlled = value !== undefined;
  const current = isControlled ? value : internalValue;

  return (
    <div className={cn("w-full", className)}>
      {(label || showValue) && (
        <div className="flex items-center justify-between gap-3 mb-2">
          {label && <label className="text-sm font-medium text-slate-700 dark:text-slate-300">{label}</label>}
          {showValue && <span className="text-xs text-slate-500 dark:text-slate-400">{Math.round(current)}</span>}
        </div>
      )}

      <input
        type="range"
        min={min}
        max={max}
        step={step}
        value={current}
        onChange={(event) => {
          const next = Number(event.target.value);
          if (!isControlled) setInternalValue(next);
          onValueChange?.(next);
        }}
        className="h-2 w-full cursor-pointer appearance-none rounded-lg bg-slate-200 accent-primary dark:bg-[#1f2937]"
      />
    </div>
  );
}
04

Props

PropTypeDefaultDescription
valuenumberControlled slider value.
defaultValuenumber50Initial value when the slider is uncontrolled.
minnumber0Minimum selectable value.
maxnumber100Maximum selectable value.
stepnumber1Increment size between slider positions.
onValueChange(value: number) => voidCalled whenever the range input value changes.
labelstringOptional label displayed above the slider track.
showValuebooleantrueDisplays the current numeric value alongside the label.
classNamestringAdditional classes applied to the root wrapper.
React Principles