Compare Slider

Animated

Drag a divider to compare two layers.

View Source

#Installation

npx @dinachi/cli@latest add compare-slider

#Usage

tsx
import { CompareSlider } from "@/components/ui/compare-slider"
tsx
<CompareSlider
  before={<img src="/before.jpg" alt="Before retouching" />}
  after={<img src="/after.jpg" alt="After retouching" />}
/>

#Examples

#Drag modes

ModeBehaviourUse it when
handleOnly the divider starts a drag. Both layers stay live: buttons take clicks, text takes selection, links take focus.Either side is real UI, or has anything in it worth clicking.
panelPressing anywhere jumps the divider there.Both sides are images. There is nothing to click, and a thin handle is a needlessly small target.

panel makes both layers inert, which reads as a bug on anything interactive. That is why it is not the default.

#When to use it

The divider works because both layers are registered: the same frame, in the same place, at the same size.

Use it forNot for
A before/after photo, a design diff, a map with a layer toggled.Two things that merely sit side by side. With nothing aligned there is nothing to reveal, and a pair of panels says it better.

#Behaviour

  • A pointer drag tracks 1:1, with no easing. That is direct manipulation, and smoothing there reads as lag.
  • A keyboard step is carried over 100ms. One press moves the divider a fixed slice of the panel, which in a single frame strobes rather than moves. A held arrow key composes into one continuous travel rather than a queue of restarts.
  • Grabbing the handle keeps your offset, so the divider does not teleport under your finger. Pressing the panel in panel mode deliberately does the opposite.
  • A second pointer mid-drag is ignored until the first lifts, rather than jumping the divider away from the finger already holding it.

#Accessibility

  • The handle is a slider with aria-valuemin, aria-valuemax and a live aria-valuenow, so the position is readable rather than only visible.
  • Arrow keys step, Shift steps five times as far, Home and End jump to either end. The announced value updates on the key press, not when the animation lands.
  • Give it a label when the panel needs saying which two things are being compared. The default, "Compare position", describes the control and not the content.
  • Reduced motion places each keyboard step immediately instead of carrying it.

#API Reference

PropTypeDefaultDescription
beforeReactNodeContent shown on the left of the divider
afterReactNodeContent shown on the right of the divider
defaultPositionnumber50Starting divider position, 0–100
stepnumber2Percentage points moved per arrow key press
drag"handle" | "panel""handle"What starts a drag. handle keeps both layers interactive
labelstring"Compare position"Accessible name for the divider handle
stickyHandlebooleanfalseKeep the knob at the vertical middle of the viewport. Set it when the panel is taller than the screen
onPositionChange(position: number) => voidFired on release and on each keyboard step