Before After Slider
A free before after slider: an image and media component that wipes between two pictures with React, Motion and Tailwind.
- Automated axe check
- Reduced-motion tested
- SSR build verified
- Motion
- 1 runtime package
Before After Slider is a free before after slider component for Next.js and React, built with Motion and styled with Tailwind. It stacks two images and reveals the second from the left with a bounded clip-path as you drag the divider, so you can compare an edit, a renovation or a design change in place.
A single transparent native range input owns every interaction and all slider semantics, which keeps it fully keyboard operable and screen-reader friendly out of the box. Pointer and touch dragging move the divider through a Motion value with no React render per sample, the handle springs to a larger size while you drag, and with prefers-reduced-motion enabled the divider still moves but does so instantly with no easing or spring.
Drag the handle, or focus it and use the arrow keys, to wipe between the two versions. Shift plus an arrow jumps in bigger steps and Home or End snaps to either edge.
Customise
Component settings update the preview and generated code together.
Content
Appearance
Behaviour
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/media-before-afterUsage
import { MediaBeforeAfter } from "@/components/media-before-after";
export function Example() {
return (
<MediaBeforeAfter
before={{ src: "/before.jpg", alt: "Room before the renovation" }}
after={{ src: "/after.jpg", alt: "Room after the renovation" }}
initial={50}
aspectRatio={16 / 9}
label="Renovation comparison"
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| before | { src: string; alt: string } | required | Base image shown underneath and revealed to the right of the divider. Its alt text stays in the accessibility tree. |
| after | { src: string; alt: string } | required | Image revealed from the left as the divider moves right. Its alt text stays in the accessibility tree. |
| initial | number | 50 | Starting divider position as a percentage, clamped to 0 to 100. |
| aspectRatio | number | 16 / 9 | Positive width divided by height ratio used to reserve layout space so there is no layout shift. |
| label | string | "Comparison slider" | Accessible name for the native range control. |
| className | string | undefined | Additional classes merged onto the wrapper. |
Customisation
Before After Slider declares no tokens of its own; the divider line and handle draw from the shared foreground, background and ring tokens so they invert with the theme, and the keyboard easing mirrors the --dur-1 and --ease-out-quart motion tokens. Reserve a different shape with the aspectRatio prop and restyle the frame from the className prop with the same semantic tokens the rest of the library uses:
<MediaBeforeAfter
before={{ src: "/before.jpg", alt: "Studio shot, unedited" }}
after={{ src: "/after.jpg", alt: "Studio shot, colour graded" }}
aspectRatio={4 / 3}
className="rounded-3xl border-2"
/>Frequently asked questions
- Is Before After Slider free for commercial use?
- Yes. Before After Slider is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is the before after slider accessible and keyboard operable?
- Yes. A single native range input owns the slider role, accessible name, minimum, maximum and current value, so screen readers announce it correctly and it never uses a fake role on a button. Arrow keys move the divider by 2 percent, Shift plus an arrow moves 10 percent, and Home and End snap to either edge, all clamped to the 0 to 100 range. The visible handle shows a focus ring driven from the range focus state, and with prefers-reduced-motion enabled every change still works but happens instantly.
- Will dragging the slider hurt performance or cause layout shift?
- No. The wrapper reserves its space from the aspectRatio prop so cumulative layout shift stays at zero, and dragging updates a Motion value directly with no React render per pointer sample. The divider only ever animates a transform and the revealed image uses a clip-path bounded to the media box, so no layout property is animated and no will-change is left behind once you stop.
Related components
More free image and media are on the way. Browse the full component library in the meantime.