GitHub

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
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