Skip to content
Sign in
MediaImage compareMenu

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.

A colorize edit. Drag the grip, click anywhere to jump, or focus the grip and use the arrow keys.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/image-compare.json

Usage

tsx
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

PropTypeNotes
before, after{ src, alt } | ReactNodeRequired
beforeLabel, afterLabelstringDefault "Original" and "Edited"
labelsbooleanShow the labels. Default true
position, defaultPosition, onPositionChangenumber0 to 100. Controlled or uncontrolled, default 50
onPositionCommit(position) => voidOnce a drag, click or key press settles
orientation"horizontal" | "vertical"Default horizontal
aspectRatio"W:H" | numberDefault 1
disabledbooleanHides the grip and ignores input

Keyboard

KeyAction
TabFocus the grip
ArrowLeft, ArrowRightMove 1% in the arrow's direction, in either reading direction
ArrowUp, ArrowDownMove 1%. When vertical, the divider follows the arrow
Shift + arrowMove 10%
PageUp, PageDownMove 10%
Home, EndAll 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 transform and the before image with clip-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.