Ratio Slider
nexvyn/ratio-sliderFreeComponent
A split ratio slider with two color bars, a draggable divider, and responsive labels that collapse when space is tight.
Live preview
live · rendered by the registry
Rendered by nexvyn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.nexvyn.dev/r/ratio-slider.jsonSource
1'use client'23import { forwardRef, useState, useRef, useCallback, useEffect, type HTMLAttributes } from 'react'4import {5 animate,6 motion,7 useMotionValue,8 useMotionValueEvent,9 useReducedMotion,10 useTransform,11} from 'motion/react'12import { cn } from '@/lib/utils'13import { springs } from '@/lib/motion-tokens'14import { playHoverSound, playClickSound, playTickSound } from '@/lib/sound'1516export interface RatioSliderProps extends Omit<17 HTMLAttributes<HTMLDivElement>,18 'onChange' | 'defaultValue'19> {20 value?: number21 defaultValue?: number22 onChange?: (value: number) => void23 min?: number24 max?: number25 step?: number26 leftLabel?: string27 rightLabel?: string28 leftColor?: string29 rightColor?: string30 leftLabelColor?: string31 rightLabelColor?: string32 disabled?: boolean33}3435function clamp(n: number, lo: number, hi: number) {36 return Math.max(lo, Math.min(hi, n))37}3839export const RatioSlider = forwardRef<HTMLDivElement, RatioSliderProps>(40 (41 {42 value,43 defaultValue = 60,44 onChange,45 min = 0,46 max = 100,47 step = 1,48 leftLabel = 'RICH',49 rightLabel = 'LIGHT',50 leftColor = 'var(--color-fg)',51 rightColor = 'var(--color-muted)',52 leftLabelColor = 'var(--color-bg)',53 rightLabelColor = 'var(--color-fg)',54 disabled = false,55 className,56 ...rest57 },58 ref,59 ) => {60 const isControlled = value !== undefined61 const [internal, setInternal] = useState(defaultValue)62 const leftRatio = isControlled ? value : internal6364 const reduceMotion = useReducedMotion()65 const [isCompact, setIsCompact] = useState(false)66 const sliderRef = useRef<HTMLDivElement>(null)67 const leftBarRef = useRef<HTMLDivElement>(null)68 const rightBarRef = useRef<HTMLDivElement>(null)69 const leftLabelRef = useRef<HTMLDivElement>(null)70 const rightLabelRef = useRef<HTMLDivElement>(null)71 const isDragging = useRef(false)72 const [draggingState, setDraggingState] = useState(false)7374 const ratio = 100 - leftRatio75 const barHeight = isCompact ? 32 : 6076 const labelsRowHeight = 3277 const gap = 1678 const edgePadding = 167980 const leftPercent = useMotionValue(leftRatio)81 const settleRef = useRef<ReturnType<typeof animate> | null>(null)82 const settleTargetRef = useRef<number | null>(null)8384 const stopSettle = useCallback(() => {85 settleRef.current?.stop()86 settleRef.current = null87 settleTargetRef.current = null88 }, [])8990// … truncated
What it pulls in
npm packages
Files it writes
More from nexvyn
All 40 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | nexvyn | Components | Free | 1 dep | |
| Action Buttonaction-button | nexvyn | Components | Free | 3 deps · 4 files | |
| Adaptive Actionsadaptive-actions | nexvyn | Components | Free | 1 dep | |
| AI Inputai-input | nexvyn | Components | Free | 1 dep · 2 files | |
| Badgebadge | nexvyn | Components | Free | 2 deps · 2 files | |
| Bars Themebars-theme | nexvyn | Components | Free | 1 dep · 3 files | |
| Bounce Sidebarbounce-sidebar | nexvyn | Components | Free | 1 dep · 2 files | |
| Breadcrumbsbreadcrumbs | nexvyn | Components | Free | 1 dep · 2 files |
