Slider
trovecn/sliderFreeComponent
Base UI slider with a spring-driven thumb — direct 1:1 tracking while dragging, a spring settle on release or track-press, and a thumb-anchored value label that fades away cleanly. Supports single-value and two-thumb range use out of the box.
Install it
npx shadcn@latest add https://trovecn.dev/r/slider.jsonSource
1"use client";23import { type ReactNode, useEffect, useRef, useState } from "react";4import { Slider as SliderPrimitive } from "@base-ui/react/slider";5import {6 AnimatePresence,7 animate,8 motion,9 useMotionValue,10 useReducedMotion,11 useTransform,12 type MotionValue,13} from "motion/react";1415import { cn } from "@/lib/utils";16import { spring } from "@/lib/springs";1718export type SliderValue = number | readonly number[];1920function defaultFormatValue(value: number) {21 return Number.isInteger(value) ? String(value) : value.toFixed(1);22}2324function percentOf(value: number, min: number, max: number) {25 return max === min ? 0 : ((value - min) / (max - min)) * 100;26}2728interface SliderProps extends Omit<SliderPrimitive.Root.Props, "children" | "orientation"> {29 className?: string;30 trackClassName?: string;31 thumbClassName?: string;32 label?: ReactNode;33 thumbLabels?: string[];34 formatValue?: (value: number) => string;35}3637function Slider({38 className,39 trackClassName,40 thumbClassName,41 label,42 thumbLabels,43 formatValue = defaultFormatValue,44 value: valueProp,45 defaultValue,46 onValueChange,47 onValueCommitted,48 min = 0,49 max = 100,50 step = 1,51 disabled = false,52 ...props53}: SliderProps) {54 const [uncontrolledValue, setUncontrolledValue] = useState<SliderValue>(55 () => defaultValue ?? min,56 );57 const value = valueProp ?? uncontrolledValue;58 const values: readonly number[] = Array.isArray(value) ? value : [value as number];59 const [dragging, setDragging] = useState(false);60 const [activeIndex, setActiveIndex] = useState(-1);6162 const motion0 = useMotionValue(percentOf(values[0] ?? min, min, max));63 const motion1 = useMotionValue(percentOf(values[1] ?? values[0] ?? min, min, max));64 const motionValues = [motion0, motion1] as const;65 const hasMountedRef = useRef(false);66 const reduceMotion = useReducedMotion();6768 useEffect(() => {69 hasMountedRef.current = true;70 }, []);7172 useEffect(() => {73 const controls = values.map((rawValue, index) => {74 const mv = motionValues[index];75 if (!mv) return undefined;76 const percent = percentOf(rawValue, min, max);77 if (!hasMountedRef.current || dragging || reduceMotion) {78 mv.set(percent);79 return undefined;80 }81 return animate(mv, percent, spring.moderate.enter);82 });83 return () => controls.forEach((control) => control?.stop());84 // motionValues are stable refs; re-run only when the actual values/range change.85// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from trovecn
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | trovecn | Components | Free | 3 deps | |
| Agent Activityagent-activity | trovecn | Components | Free | 2 deps | |
| Approval Requestapproval-request | trovecn | Components | Free | 2 deps | |
| Buttonbutton | trovecn | Components | Free | 2 deps | |
| Checkboxcheckbox | trovecn | Components | Free | 2 deps | |
| Checkbox Groupcheckbox-group | trovecn | Components | Free | 2 deps | |
| Comboboxcombobox | trovecn | Components | Free | 3 deps | |
| Comparison Slidercomparison-slider | trovecn | Components | Free | 1 dep |
