ComparisonSlider
comparisonslider-1779379671626.tsx
'use client'
import { useState, useRef, useCallback, useEffect } from 'react'
export default function ComparisonSlider() {
const [position, setPosition] = useState(50)
const [dragging, setDragging] = useState(false)
const containerRef = useRef<HTMLDivElement>(null)
const handleMove = useCallback((clientX: number) => {
if (!containerRef.current) return
const rect = containerRef.current.getBoundingClientRect()
const pct = ((clientX - rect.left) / rect.width) * 100
setPosition(Math.max(0, Math.min(100, pct)))
}, [])
useEffect(() => {
if (!dragging) return
const onMove = (e: MouseEvent | TouchEvent) => {
const x = 'touches' in e ? e.touches[0].clientX : e.clientX
handleMove(x)
}
const onUp = () => setDragging(false)
window.addEventListener('mousemove', onMove)
window.addEventListener('touchmove', onMove)
window.addEventListener('mouseup', onUp)
window.addEventListener('touchend', onUp)
return () => {
window.removeEventListener('mousemove', onMove)
window.removeEventListener('touchmove', onMove)
window.removeEventListener('mouseup', onUp)
window.removeEventListener('touchend', onUp)
}
}, [dragging, handleMove])
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === 'ArrowLeft') setPosition(p => Math.max(0, p - 5))
if (e.key === 'ArrowRight') setPosition(p => Math.min(100, p + 5))
}
document.addEventListener('keydown', handler)
return () => document.removeEventListener('keydown', handler)
}, [])
return (
<div style={{ padding: 32, background: '#0A0A0A', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20 }}>
<div style={{ color: '#F5F5F0', fontSize: 16, fontWeight: 700 }}>Before / After</div>
<div ref={containerRef} onMouseDown={e => { setDragging(true); handleMove(e.clientX) }}
onTouchStart={e => { setDragging(true); handleMove(e.touches[0].clientX) }}
style={{ position: 'relative', width: 480, height: 280, borderRadius: 16, overflow: 'hidden', cursor: 'col-resize', userSelect: 'none', border: '1px solid rgba(255,255,255,0.08)' }}>
{/* "Before" side — dark code editor */}
<div style={{ position: 'absolute', inset: 0, background: '#111', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 8 }}>
<div style={{ background: '#1a1a1a', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 12, padding: 20, width: 200, fontFamily: 'monospace', fontSize: 11 }}>
{['<Button>', ' style={{', ' padding: 8,', ' color: 'white'', ' }}', '>Click</Button>'].map((l, i) => (
<div key={i} style={{ color: i === 0 || i === 5 ? '#C9A84C' : 'rgba(255,255,255,0.5)', marginBottom: 2 }}>{l}</div>
))}
</div>
<div style={{ color: 'rgba(255,255,255,0.3)', fontSize: 12 }}>Writing from scratch</div>
</div>
{/* "After" side — Empire UI */}
<div style={{ position: 'absolute', inset: 0, clipPath: `inset(0 ${100 - position}% 0 0)`, background: 'linear-gradient(135deg, #0A0A0A, #0d0817)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 8 }}>
<div style={{ background: 'rgba(201,168,76,0.08)', border: '1px solid rgba(201,168,76,0.2)', borderRadius: 12, padding: 20, width: 200, display: 'flex', flexDirection: 'column', gap: 10 }}>
<div style={{ display: 'flex', gap: 6 }}>
{['⬡', '⊞', '◎'].map((i, idx) => (
<div key={idx} style={{ flex: 1, height: 28, background: 'rgba(201,168,76,0.1)', border: '1px solid rgba(201,168,76,0.2)', borderRadius: 6, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14 }}>{i}</div>
))}
</div>
<div style={{ height: 8, background: 'rgba(255,255,255,0.06)', borderRadius: 4 }} />
<div style={{ height: 8, width: '70%', background: 'rgba(255,255,255,0.04)', borderRadius: 4 }} />
<div style={{ background: '#C9A84C', borderRadius: 6, padding: '6px', textAlign: 'center', color: '#0A0A0A', fontWeight: 700, fontSize: 12 }}>GlowButton</div>
</div>
<div style={{ color: 'rgba(201,168,76,0.7)', fontSize: 12 }}>Using Empire UI MCP</div>
</div>
{/* Labels */}
<div style={{ position: 'absolute', top: 12, left: 12, background: 'rgba(0,0,0,0.7)', color: 'rgba(255,255,255,0.6)', padding: '3px 8px', borderRadius: 4, fontSize: 11, fontWeight: 600 }}>BEFORE</div>
<div style={{ position: 'absolute', top: 12, right: 12, background: 'rgba(201,168,76,0.2)', color: '#C9A84C', padding: '3px 8px', borderRadius: 4, fontSize: 11, fontWeight: 600 }}>AFTER</div>
{/* Handle */}
<div style={{ position: 'absolute', top: 0, bottom: 0, left: `${position}%`, width: 2, background: '#C9A84C', transform: 'translateX(-50%)' }}>
<div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 36, height: 36, background: '#C9A84C', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 0 16px rgba(201,168,76,0.5)' }}>
<span style={{ color: '#0A0A0A', fontSize: 14 }}>⇔</span>
</div>
</div>
{/* Percent overlay */}
<div style={{ position: 'absolute', bottom: 12, left: '50%', transform: 'translateX(-50%)', background: 'rgba(0,0,0,0.7)', color: '#F5F5F0', padding: '3px 10px', borderRadius: 20, fontSize: 11 }}>
{Math.round(position)}% · drag or use arrow keys
</div>
</div>
</div>
)
}Component info
CategoryData Display
Frameworkreact
TierFREE
Views0
Copies0
About
Before/after image comparison slider with drag handle, percentage overlay, and keyboard support
More from Data Display
'use client'
import { useState } from 'react'
const WEEKS = 26
const DAYS = 7
function randomActivity(): number {
const r = Math.random()
if (r < 0.3) return 0
if (r < 0.55) return 1
if (r < 0.75) return 2
if (r < 0.9) return 3
return 4HeatmapCalendar
Data Display
'use client'
import { useState } from 'react'
const events = [
{ id: 1, icon: '🚀', title: 'Wave 7 generation complete', desc: '57 new components published across 14 categories', time: '14:32', type: 'success', day: 'Today' },
{ id: 2, icon: '👥TimelineActivity
Data Display