July 31, 2026
Deltaphoto
A small image comparison component for React. Give it two photos and it handles the rest.


I kept needing the same interaction: compare a redesign, show a restoration, explain an edit, or make a visual change obvious without asking someone to flip between two images. The available components worked, but most of them felt like unfinished plumbing rather than something I wanted to put on a page.
So I made the version I wanted to reach for: deliberately small, already designed, and useful without a setup screen full of decisions.
Getting started
The finished API is only two required props. Everything else is an optional refinement for a particular comparison.
import { Deltaphoto } from "deltaphoto";
import "deltaphoto/styles.css";
<Deltaphoto
before="/room-before.jpg"
after="/room-after.jpg"
/>It fills the width of its parent and keeps a 3:2 aspect ratio by default. The component ships with its interaction styles, so the surrounding layout is entirely yours.
The interaction
The divider is built on a native range input. That means the same control works with a mouse, a finger, a trackpad, and a keyboard instead of maintaining a separate path for each one.
Drag anywhere
The full image is the target, not just the small handle.
Scroll naturally
Vertical page movement stays available on touch screens.
Keyboard stops
Arrow keys jump cleanly between the start, middle, and end.
Smooth drag
The divider eases toward the pointer without lagging behind it.
Making it yours
The defaults are meant to be the version you ship. The options are there for real content differences—labels, framing, and controlled state—not for rebuilding the component piece by piece.
<Deltaphoto
before="/kitchen-old.jpg"
after="/kitchen-new.jpg"
beforeLabel="Original"
afterLabel="Renovated"
initialPosition={38}
aspectRatio="16 / 10"
foregroundColor="#f7f3ea"
backgroundColor="#1b1a18"
/>Pass a class name or normal inline styles to the root when the comparison needs a different radius or surrounding treatment. Both images always share the same crop, which keeps the comparison visually honest.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
before | string | required | URL for the image shown on the left. |
after | string | required | URL for the image shown on the right. |
beforeAlt | string | "Before" | Alternative text for the before image. |
afterAlt | string | "After" | Alternative text for the after image. |
beforeLabel | string | "Before" | Label shown over the before image. |
afterLabel | string | "After" | Label shown over the after image. |
showLabels | boolean | true | Show or hide both image labels. |
initialPosition | number | 50 | Initial divider position from 0 to 100. |
position | number | — | Controlled divider position from 0 to 100. |
onPositionChange | function | — | Runs whenever the divider moves. |
aspectRatio | CSS value | "3 / 2" | Aspect ratio of the comparison surface. |
objectFit | CSS value | "cover" | How both images fit inside the surface. |
foregroundColor | CSS color | "#000" | Color used for the grip and component text. |
backgroundColor | CSS color | "#fff" | Color used for labels, the divider, and the handle. |
ariaLabel | string | comparison description | Accessible name for the range control. |
className | string | "" | Class applied to the root element. |
Standard div attributes, including data attributes and event handlers, are passed to the root element.
Package status
The component is working and packaged locally. I am using it on this page before publishing it more broadly—the best way to find the awkward edges is to depend on it yourself.
The npm release is still to come. Until then, this page is the source of truth for what the component is meant to do.