Image compare
Before and after for edits and upscales, split by a draggable hairline. Drag, click to jump or use the keyboard, horizontal or vertical, with labels that step aside near the handle.
On this page
A colorize edit. Drag the grip, click anywhere to jump, or focus the grip and use the arrow keys.
Installation
Usage
import { ImageCompare } from "@/components/ui/chatcn/image-compare"
<ImageCompare
aspectRatio="3:2"
before={{ src: original, alt: "The original photo" }}
after={{ src: edited, alt: "The photo with the sky replaced" }}
/>before and after take an image ({ src, alt }) or any node that fills the frame: a canvas, a video still, or an image drawn your own way. position is how much of before shows, from 0 to 100, measured from the start edge (the right edge in right-to-left layouts) or from the top when vertical.
Examples
Upscale
A 240 px source drawn pixelated through the before slot, against the upscaled result.
Vertical
Top and bottom for portrait frames, moved with the up and down arrows.
States
Controlled from outside, disabled, and an edited file that fails to load.
Props
| Prop | Type | Notes |
|---|---|---|
before, after | { src, alt } | ReactNode | Required |
beforeLabel, afterLabel | string | Default "Original" and "Edited" |
labels | boolean | Show the labels. Default true |
position, defaultPosition, onPositionChange | number | 0 to 100. Controlled or uncontrolled, default 50 |
onPositionCommit | (position) => void | Once a drag, click or key press settles |
orientation | "horizontal" | "vertical" | Default horizontal |
aspectRatio | "W:H" | number | Default 1 |
disabled | boolean | Hides the grip and ignores input |
Keyboard
| Key | Action |
|---|---|
Tab | Focus the grip |
ArrowLeft, ArrowRight | Move 1% in the arrow's direction, in either reading direction |
ArrowUp, ArrowDown | Move 1%. When vertical, the divider follows the arrow |
Shift + arrow | Move 10% |
PageUp, PageDown | Move 10% |
Home, End | All after, all before |
Accessibility
- The grip is a slider named after the two labels, for example Compare original and colorized, with a value text such as Original 62%, colorized 38%.
- Both images keep their
alt. The visible labels are decorative copies and hidden from screen readers. - The grip is 20 by 28 px with a 40 px hit area, 44 px on touch screens. Clicking anywhere moves focus to it, so the arrow keys work straight after.
- On touch, a vertical swipe still scrolls the page. A drag starts after 6 px of sideways travel, and a tap jumps.
Motion
- Only a click or tap to jump glides, over 180 ms. Drags track the pointer 1:1 and keys move instantly.
- The divider moves with
transformand the before image withclip-path, never layout properties. - Labels fade out in 150 ms when the handle comes within their width. Reduced motion keeps the fades and drops the glide.