Compare Slider
loomui/compare-sliderFreeComponent
Two versions of the same frame, split by a divider you drag, or move with the arrow keys.
Live preview
live · rendered by the registry
Rendered by loomui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://loomui.design/r/compare-slider.jsonSource
1"use client"23import * as React from "react"45import { cn } from "@/lib/utils"67export interface CompareSliderProps extends Omit<8 React.ComponentProps<"div">,9 "onChange"10> {11 /** Sits in flow and sets the size of the frame. Shown before the divider. */12 before: React.ReactNode13 /** Laid over the top and clipped to after the divider. */14 after: React.ReactNode15 /** Divider position, 0 to 100. Leave it out to let the slider own it. */16 position?: number17 /** Starting position when the slider owns it. */18 defaultPosition?: number19 /** Called with the position the divider moved to. */20 onPositionChange?: (position: number) => void21 /** Split left to right, or top to bottom. */22 orientation?: "horizontal" | "vertical"23 /** Percent moved per arrow key. Shift moves five of these. */24 step?: number25 /** Name for the divider, which is a real slider. */26 label?: string27}2829const clamp = (value: number) => Math.min(Math.max(value, 0), 100)3031export function CompareSlider({32 before,33 after,34 position,35 defaultPosition = 50,36 onPositionChange,37 orientation = "horizontal",38 step = 2,39 label = "Compare",40 className,41 style,42 ...props43}: CompareSliderProps) {44 const [own, setOwn] = React.useState(defaultPosition)45 const [dragging, setDragging] = React.useState(false)46 const frameRef = React.useRef<HTMLDivElement>(null)4748 const isControlled = position !== undefined49 const value = clamp(isControlled ? position : own)50 const vertical = orientation === "vertical"5152 const commit = (next: number) => {53 const clamped = clamp(next)54 if (!isControlled) {55 setOwn(clamped)56 }57 onPositionChange?.(clamped)58 }5960 const trackPointer = (event: React.PointerEvent<HTMLDivElement>) => {61 const frame = frameRef.current62 if (!frame) {63 return64 }65 const rect = frame.getBoundingClientRect()66 const ratio = vertical67 ? (event.clientY - rect.top) / rect.height68 : (event.clientX - rect.left) / rect.width69 commit(ratio * 100)70 }7172 const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {73 const distance = event.shiftKey ? step * 5 : step74 const back = vertical ? "ArrowUp" : "ArrowLeft"75 const forward = vertical ? "ArrowDown" : "ArrowRight"7677 if (event.key === back) {78 commit(value - distance)79 } else if (event.key === forward) {80 commit(value + distance)81 } else if (event.key === "Home") {82 commit(0)83 } else if (event.key === "End") {84 commit(100)85// … truncated
What it pulls in
Other registry items
Files it writes
More from loomui
All 91 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Aurora Backdropaurora-backdrop | loomui | Components | Free | no deps | |
| Bento Gridbento-grid | loomui | Components | Free | no deps | |
| Card Stackcard-stack | loomui | Components | Free | no deps | |
| Confetti Buttonconfetti-button | loomui | Components | Free | no deps | |
| Count Upcount-up | loomui | Components | Free | no deps | |
| Credit Cardcredit-card | loomui | Components | Free | no deps | |
| Drawerdrawer | loomui | Components | Free | 1 dep | |
| Elastic Tabselastic-tabs | loomui | Components | Free | no deps |
