FluxUI Pro is live - modern UI, powerful animations, zero hassle.
Components
Interactive Slider

Interactive Slider

Smooth range sliders with animated thumbs, value indicators, and customizable styling.

Volume
65
65
Brightness
80
80
Speed
45
45

Installation

1

Install the packages

npm i motion clsx tailwind-merge
2

Add util file

lib/util.ts
import { ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
3

Copy and paste the following code into your project

interactive-slider.tsx
"use client"; import { motion } from "motion/react"; import { useState, useRef, useEffect } from "react"; import { cn } from "@/lib/utils"; type InteractiveSliderProps = { min?: number; max?: number; value?: number; onChange?: (value: number) => void; }; const InteractiveSlider = ({ min = 0, max = 100, value: initialValue = 50, onChange = () => {}, }: InteractiveSliderProps) => { const [value, setValue] = useState(initialValue); const [isDragging, setIsDragging] = useState(false); const sliderRef = useRef<HTMLDivElement>(null); const handleMouseDown = (e: React.MouseEvent) => { setIsDragging(true); updateValue(e.clientX); }; const handleMouseMove = (e: MouseEvent) => { if (isDragging) { updateValue(e.clientX); } }; const handleMouseUp = () => { setIsDragging(false); }; const updateValue = (clientX: number) => { if (sliderRef.current) { const rect = sliderRef.current.getBoundingClientRect(); const percentage = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width)); const newValue = Math.round(min + percentage * (max - min)); setValue(newValue); onChange(newValue); } }; useEffect(() => { if (isDragging) { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; } }, [isDragging]); const percentage = ((value - min) / (max - min)) * 100; return ( <div className="w-full max-w-md mx-auto"> <div className="mb-6"> <div className="flex justify-between items-center mb-2"> <span className="text-sm font-medium text-neutral-700 dark:text-neutral-300"> Value: {value} </span> <span className="text-xs text-neutral-500"> {min} - {max} </span> </div> <div ref={sliderRef} className="relative h-6 bg-neutral-200 dark:bg-neutral-700 rounded-full cursor-pointer" onMouseDown={handleMouseDown} > {/* Track */} <div className="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full opacity-20" /> {/* Progress */} <motion.div className="absolute left-0 top-0 h-full bg-gradient-to-r from-blue-500 to-purple-500 rounded-full" initial={{ width: 0 }} animate={{ width: `${percentage}%` }} transition={{ duration: 0.1 }} /> {/* Thumb */} <motion.div className="absolute top-1/2 -translate-y-1/2 w-6 h-6 bg-white border-2 border-blue-500 rounded-full shadow-lg cursor-grab active:cursor-grabbing" style={{ left: `calc(${percentage}% - 12px)` }} whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.95 }} animate={{ boxShadow: isDragging ? "0 0 20px rgba(59, 130, 246, 0.5)" : "0 2px 8px rgba(0, 0, 0, 0.1)", }} transition={{ duration: 0.2 }} /> {/* Value indicator */} <motion.div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-neutral-900 dark:bg-neutral-100 text-white dark:text-neutral-900 px-2 py-1 rounded text-xs font-medium" style={{ left: `${percentage}%` }} initial={{ opacity: 0, y: -5 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.2 }} > {value} </motion.div> </div> </div> </div> ); }; export default InteractiveSlider;
4

Update the import paths to match your project setup

Props

PropTypeDefaultDescription
minnumber0The minimum value of the slider.
maxnumber100The maximum value of the slider.
valuenumber50The current value of the slider.