ReUI
Components

Slider

An input where the user selects a value from within a given range.

Installation

Install ReUI

Refer to the Installation Guide for detailed instructions on setting up ReUI dependencies in your project.

Install dependencies

npm install @radix-ui/react-slider

Add component

Copy and paste the following code into your project’s components/ui/slider.tsx file.

'use client';

import * as React from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';
import { cn } from '@/lib/utils';

function Slider({
  className,
  children,
  ...props
}: React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>) {
  return (
    <SliderPrimitive.Root
      data-slot="slider"
      className={cn(
        'relative flex h-4 w-full touch-none select-none items-center',
        className,
      )}
      {...props}
    >
      <SliderPrimitive.Track className="relative h-1.5 w-full overflow-hidden rounded-full bg-accent">
        <SliderPrimitive.Range className="absolute h-full bg-primary" />
      </SliderPrimitive.Track>
      {children}
    </SliderPrimitive.Root>
  );
}

function SliderThumb({
  className,
  ...props
}: React.ComponentPropsWithoutRef<typeof SliderPrimitive.Thumb>) {
  return (
    <SliderPrimitive.Thumb
      data-slot="slider-thumb"
      className={cn(
        'box-content block size-4 shrink-0 cursor-pointer rounded-full border-[2px] border-primary bg-primary-foreground shadow-xs shadow-black/5 outline-hidden focus:outline-hidden',
        className,
      )}
      {...props}
    />
  );
}

export { Slider, SliderThumb };

Add hook

Copy and paste the following code into your project’s hooks/use-slider-input.ts file.

import * as React from 'react';
import { useCallback, useState } from 'react';

interface UseSliderInputProps {
  minValue: number;
  maxValue: number;
  initialValue: [number, number];
}

export function useSliderInput({
  minValue,
  maxValue,
  initialValue,
}: UseSliderInputProps) {
  const [sliderValues, setSliderValues] =
    useState<[number, number]>(initialValue);
  const [inputValues, setInputValues] =
    useState<[number, number]>(initialValue);

  // Handle slider changes and sync with input values
  const handleSliderChange = useCallback((values: [number, number]) => {
    setSliderValues(values);
    setInputValues(values);
  }, []);

  // Handle input changes for min or max
  const handleInputChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>, index: 0 | 1) => {
      const newValue = parseFloat(e.target.value);
      if (!isNaN(newValue)) {
        const updatedInputs = [...inputValues] as [number, number];
        updatedInputs[index] = newValue;
        setInputValues(updatedInputs);
      }
    },
    [inputValues],
  );

  // Validate and update slider values when input loses focus or user presses Enter
  const validateAndUpdateValue = useCallback(
    (value: number, index: 0 | 1) => {
      const updatedSlider = [...sliderValues] as [number, number];

      if (index === 0) {
        // Min value
        updatedSlider[0] = Math.max(minValue, Math.min(value, sliderValues[1]));
      } else {
        // Max value
        updatedSlider[1] = Math.min(maxValue, Math.max(value, sliderValues[0]));
      }

      setSliderValues(updatedSlider);
      setInputValues(updatedSlider);
    },
    [sliderValues, minValue, maxValue],
  );

  return {
    setSliderValues,
    setInputValues,
    sliderValues,
    inputValues,
    handleSliderChange,
    handleInputChange,
    validateAndUpdateValue,
  };
}

Examples

Default

Loading

Range

Loading

Tooltip

Loading

Input

Loading

Form

Loading

API Reference

This component is built using Radix UI Slider primitives. For detailed information, please visit the full API reference.

Slider

This component is based on the Slider.Root primitive. For full details, visit the official documentation.

SliderThumb

This component is based on the Slider.Thumb primitive. For full details, visit the official documentation.