Image compare
Drag a divider across two images to see what changed.
before aftercomparisonimage
Preview
Image compare preview
Live · keyboard ready
Retouched
Original
When to use
- Before and after visuals such as photo edits, redesigns, or cleanup results.
- Top and bottom comparisons, via orientation vertical.
When not to use
- Use carousel to browse many images.
- Use resizable-panels to split live content rather than images.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "image-compare",
"type": "registry:ui",
"title": "Image compare",
"description": "Drag a divider across two images to see what changed.",
"categories": [
"data"
],
"dependencies": [
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/image-compare/image-compare.tsx",
"type": "registry:component",
"target": "@components/manicat/image-compare/image-compare.tsx"
},
{
"path": "registry/components/image-compare/image-compare.module.css",
"type": "registry:component",
"target": "@components/manicat/image-compare/image-compare.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/image-compare",
"meta": {
"tier": "free",
"kind": "component",
"docs": "https://manicat.viraza.net/components/image-compare",
"markdown": "https://uiarc.dev/components/image-compare/markdown",
"tags": [
"before after",
"comparison",
"image"
]
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { ImageCompare } from "@/components/manicat/image-compare/image-compare";
export function ImageCompareExample() {
return (
<ImageCompare
aspectRatio="16/10"
labels={["Original", "Retouched"]}
before={
<div className="flex h-full w-full items-center justify-center bg-[linear-gradient(135deg,#1e3a5f,#3b5b8c)]">
<span className="text-sm font-medium text-white/80">Original</span>
</div>
}
after={
<div className="flex h-full w-full items-center justify-center bg-[linear-gradient(135deg,#0ea5e9,#22c55e)]">
<span className="text-sm font-medium text-white/80">Retouched</span>
</div>
}
/>
);
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Before and after Drag the handle to compare an original and its retouched version. Swap the gradients for real images.
Before and after
Drag the handle to compare an original and its retouched version. Swap the gradients for real images. preview
Live · keyboard ready
before-and-after-drag-the-handle-to-compare-an-original-and-its-retouched-version-swap-the-gradients-for-real-images-.tsxtsx
"use client";
import { ImageCompare } from "@/components/manicat/image-compare/image-compare";
export function ImageCompareRetouchExample() {
return (
<div className="w-full max-w-xl">
<ImageCompare
aspectRatio="16/10"
labels={["Original", "Retouched"]}
before={<div className="h-full w-full bg-[linear-gradient(135deg,#1e3a5f,#3b5b8c)]" />}
after={<div className="h-full w-full bg-[linear-gradient(135deg,#0ea5e9,#22c55e)]" />}
/>
</div>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| Arrow keys | Moves the divider by 1 percent, or 10 with Shift. |
| PageUp / PageDown | Moves the divider by 10 percent. |
| Home / End | Shows all of the before or all of the after image. |
| Double click | On the handle, recenters the divider. |
Accessibility
- The handle is a focusable role="slider" with aria-orientation and aria-valuetext like "40% after".
- Caption chips are aria-hidden; give both images meaningful alt text.
- Dragging works anywhere on the frame, not only on the handle.
Motion
- The divider follows the pointer and settles with release velocity; the handle stretches into a capsule while dragging.
- Keyboard presses at an edge give a small bump; captions fade as the divider reaches them.
- Reduced motion jumps the divider and handle without springs.
Responsive behavior
- The frame is full width with a fixed aspect ratio, so it scales to any column.
- On touch the photo waits for a sideways drag before moving the divider, so vertical swipes still scroll the page; a tap jumps the divider there.
Performance
- The divider runs on motion values and one ResizeObserver, with no React re-render per drag frame.
- Both images stay mounted and stacked, so size them for the frame.
Notes for AI
- Use for visual diffs: photo edits, redesigns, before and after results. Use carousel to browse many images.
- Both images should share the same crop and size so the reveal lines up.