Before After Comparison Slider
Draggable before/after slider with shimmer handle for visual comparisons. Light/Dark compatible.
Installation
Add this component to your project using the CLI:
npx vui-registry-cli-v1 add before-after-comparison-sliderSource Code
'use client'
import React, { useEffect, useRef, useState } from 'react'
import { motion, useMotionValue, useSpring, useTransform } from 'framer-motion'
export default function PremiumImageSlider() {
const containerRef = useRef<HTMLDivElement>(null)
const [dims, setDims] = useState({ width: 0, height: 0 })
const x = useMotionValue(0)
const springX = useSpring(x, { stiffness: 450, damping: 40 })
// Calculate the clipping mask for the colored image
const clipPath = useTransform(springX, (val) => `inset(0 0 0 ${val}px)`)
useEffect(() => {
if (containerRef.current) {
const { clientWidth, clientHeight } = containerRef.current
setDims({ width: clientWidth, height: clientHeight })
x.set(clientWidth / 2)
}
}, [x])
const handleDrag = (_: any, info: any) => {
const rect = containerRef.current?.getBoundingClientRect()
if (rect) {
const newX = Math.max(0, Math.min(info.point.x - rect.left, dims.width))
x.set(newX)
}
}
// Placeholder images - Replace with your own high-res URLs
const imageUrl = "https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=2070&auto=format&fit=crop"
return (
<div className="w-full grid place-items-center py-16">
{/* OUTER GLASS BORDER */}
<div className="p-[1px] rounded-[2.2rem] bg-gradient-to-b from-black/20 to-transparent shadow-2xl">
{/* INNER THIN BORDER */}
<div className="p-1 rounded-[2.1rem] bg-white border border-black/[0.03] shadow-inner">
<div
ref={containerRef}
className="relative w-[340px] h-[450px] sm:w-[550px] sm:h-[400px] rounded-[1.8rem] overflow-hidden bg-neutral-100 select-none shadow-2xl"
>
{/* LAYER 1: BEFORE (Black & White) */}
<div className="absolute inset-0 z-0">
<img
src={imageUrl}
alt="Before"
className="w-full h-full object-cover grayscale brightness-90"
/>
<div className="absolute inset-0 bg-black/10" />
</div>
{/* LAYER 2: AFTER (Color + Masked) */}
<motion.div
className="absolute inset-0 z-10"
style={{ clipPath }}
>
<img
src={imageUrl}
alt="After"
className="w-full h-full object-cover"
style={{ width: dims.width }}
/>
</motion.div>
{/* FLOATING GLOW DOTS (SVG) */}
<div className="absolute inset-0 z-20 pointer-events-none">
<svg width="100%" height="100%">
<defs>
<filter id="softGlow">
<feGaussianBlur stdDeviation="2" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
{[...Array(8)].map((_, i) => (
<motion.circle
key={i}
r="1.5"
fill="white"
filter="url(#softGlow)"
initial={{ x: Math.random() * 550, y: Math.random() * 400 }}
animate={{ opacity: [0.1, 0.4, 0.1], scale: [1, 1.2, 1] }}
transition={{ duration: 3 + i, repeat: Infinity }}
/>
))}
</svg>
</div>
{/* THE PREMIUM HANDLE */}
<motion.div
drag="x"
dragConstraints={containerRef}
dragElastic={0}
onDrag={handleDrag}
style={{ x: springX }}
className="absolute inset-y-0 -ml-[1.5px] w-[3px] z-30 cursor-ew-resize bg-white shadow-[0_0_15px_rgba(0,0,0,0.3)]"
>
{/* Central Trigger */}
<div className="absolute top-1/2 -left-5 -translate-y-1/2">
<motion.div
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="w-10 h-10 rounded-2xl bg-white/90 backdrop-blur-md border border-black/5 shadow-xl flex items-center justify-center"
>
<div className="flex gap-1">
<div className="w-[1.5px] h-4 bg-black/20 rounded-full" />
<div className="w-[1.5px] h-4 bg-black/60 rounded-full" />
<div className="w-[1.5px] h-4 bg-black/20 rounded-full" />
</div>
</motion.div>
</div>
</motion.div>
{/* MINI LABELS */}
<div className="absolute top-5 left-5 z-20">
<span className="text-[9px] uppercase tracking-[0.3em] font-bold text-white bg-black/20 backdrop-blur-md px-2 py-1 rounded-md border border-white/10">
Legacy
</span>
</div>
<div className="absolute top-5 right-5 z-20">
<span className="text-[9px] uppercase tracking-[0.3em] font-bold text-black bg-white/40 backdrop-blur-md px-2 py-1 rounded-md border border-black/5">
Enhanced
</span>
</div>
</div>
</div>
</div>
</div>
)
}Props
Component property reference.
| Name | Type | Default | Description |
|---|---|---|---|
| beforeSrc | string | - | Image source for the “before” side. |
| afterSrc | string | - | Image source for the “after” side. |
| className | string | - | Additional CSS classes. |
Most components here are inspired by outstanding libraries and creators in the ecosystem. I don’t claim to be the original author — this is my space for learning, rebuilding, and understanding great work at a deeper level.
I’m still a student of the craft, constantly studying the best and translating what I learn through my own perspective. Every piece reflects curiosity, respect for the community, and small creative touches that feel true to me.
I’ve done my best to credit inspirations properly. If anything is missing or inaccurate, I truly appreciate a message so it can be corrected with care.

