Image Comparison is a before and after slider built from three composable pieces: an ImageSlider container, ImageLayer panels for each side, and a Divider with a draggable handle. You can drag the handle, switch to hover control, or run it vertically, and the divider movement is driven by a Framer Motion spring so it feels weighted rather than linear. Built with React and Tailwind CSS. Ideal for photo retouching showcases, redesign comparisons, and product demos where showing the difference between two states is the whole point.
Installation
Usage
import {
ImageSlider,
ImageLayer,
Divider,
} from "@/components/ui/image-comparison";<ImageSlider className="h-96 w-full overflow-hidden rounded-xl">
<ImageLayer
src="/path/to/before-image.jpg"
alt="Before Image"
layer="first"
/>
<ImageLayer src="/path/to/after-image.jpg" alt="After Image" layer="second" />
<Divider />
</ImageSlider>/* Hover-controlled */
<ImageSlider
className="h-96 w-full overflow-hidden rounded-xl"
hoverControl={true}
defaultPosition={20}
>
<ImageLayer src="/path/to/before.jpg" alt="Before" layer="first" />
<ImageLayer src="/path/to/after.jpg" alt="After" layer="second" />
<Divider width={4} handleSize={32} />
</ImageSlider>Props
ImageSlider
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | undefined | Content of the slider, typically ImageLayer components and a Divider |
className | string | undefined | Additional CSS classes to apply to the container |
hoverControl | boolean | false | Whether to control the slider by hovering instead of dragging |
orientation | "horizontal" | "vertical" | "horizontal" | The orientation of the slider |
defaultPosition | number | 50 | The initial position of the divider as a percentage (0-100) |
animationConfig | Partial<AnimationOptions> | { damping: 15, stiffness: 400, mass: 0.4 } | Framer Motion spring animation options for the slider movement |
dividerColor | string | "#ffffff" | Color of the divider line |
constrainToContent | boolean | false | Whether to constrain the slider drag to the content area |
ImageLayer
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS classes to apply to the image |
alt | string | Required | Alt text for the image (required for accessibility) |
src | string | Required | Source URL of the image |
layer | "first" | "second" | Required | Which side of the divider this image appears on |
loading | "lazy" | "eager" | "eager" | Image loading behavior |
priority | boolean | false | Whether the image should be considered high priority for loading |
Divider
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS classes to apply to the divider |
children | React.ReactNode | undefined | Custom content to display in the handle |
width | number | 2 | Width of the divider line in pixels |
showHandle | boolean | true | Whether to show the handle on the divider |
handleSize | number | 24 | Size of the handle in pixels |
handleColor | string | undefined | Color of the handle (defaults to divider color if not specified) |
handleIcon | React.ReactNode | undefined | Custom icon to display in the handle |
hitAreaSize | number | 20 | Size of the invisible hit area around the divider |
Related components
- Image Scanner
A component for scanning images with a futuristic effect.
- Music Player
An immersive music player with morphing collapse/expand animation, glass controls, and queue management.
- Water Ripple Effect
A mesmerizing water ripple effect for interactive images.
- 3D Layered Card
A 3D card with layered effects and animations.


