webdevpuneet.com

Image Comparison Slider — Free HTML CSS JS Snippet

Before / After Slider · Media · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="scene">
  <p class="label-top">Drag the slider to compare</p>
  <div class="compare" id="compare">
    <div class="side before">
      <div class="img-sim before-sim"></div>
      <span class="tag">Before</span>
    </div>
    <div class="side after" id="after">
      <div class="img-sim after-sim"></div>
      <span class="tag">After</span>
    </div>
    <div class="handle" id="handle">
      <div class="line"></div>
      <div class="knob">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="15 18 9 12 15 6"/></svg>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="9 18 15 12 9 6"/></svg>
      </div>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

clip-path: inset(0 X% 0 0) reveals the after image from the left as the handle moves
setPos() converts clientX to a container-relative percentage
pct clamped to 5-95% to keep handle visible at extremes
mousedown/mousemove/mouseup for desktop drag
touchstart/touchmove for mobile touch drag via e.touches[0].clientX
user-select: none and cursor: col-resize prevent text selection during drag
Both images absolutely positioned to fill the same container
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

Image Comparison Slider — clip-path Reveal, Drag Handle & Touch Events

Screenshot of the Before / After Slider snippet rendered live

A before/after image comparison slider lets users drag a handle to reveal two different versions of the same image side by side — a before and after of a photo edit (as from the image filter editor), an AI enhancement, a design change, or a product transformation. This snippet implements the complete interaction: drag handle, clip-path reveal, mouse and touch events, and percentage clamping.

The clip-path reveal technique

Both images are absolutely positioned to fill the same container. The .before image (left side) is always fully visible as the background. The .after image (right side) has clip-path: inset(0 X% 0 0) — this clips its right edge by a percentage. As the handle moves left, X% increases (more of the after image is revealed from the left); as the handle moves right, X% decreases.

The setPos function

setPos(x) converts an absolute clientX position to a percentage of the container width: pct = ((x - rect.left) / rect.width) * 100. The percentage is clamped between 5% and 95% to prevent the handle from reaching the extreme edges. after.style.clipPath = "inset(0 ${100-pct}% 0 0)" and handle.style.left = pct + '%' update both the reveal and the handle position.

Mouse and touch support

mousedown sets dragging = true. mousemove calls setPos(e.clientX) while dragging is true. mouseup and mouseleave set dragging = false. touchstart and touchmove mirror this with e.touches[0].clientX.

The clip-path reveal technique

The "after" image sits directly on top of the "before" image using position: absolute; inset: 0. clip-path: inset(0 X% 0 0) clips the right portion of the after image — X% is the drag position as a percentage of the container width. When X is 50%, the left half shows "after" and the right half shows "before". When X is 0%, the full before image is visible; at 100%, the full after image is visible. Both images have the same dimensions, so the clip reveals exactly the correct portion.

Mouse and touch drag handling

The drag handle tracks three events: mousedown (start drag), mousemove (update position), mouseup (stop drag). Touch events use touchstart, touchmove, touchend. The position is computed as (e.clientX - rect.left) / rect.width * 100, clamped between 2 and 98 to prevent the images from fully disappearing. During drag, iframes have pointer-events: none applied to prevent them from intercepting mouse events.

Customising with real images

Replace the gradient placeholder divs with real img elements or background-image CSS, as you would in a photo gallery or image lightbox. Ensure both images have the same dimensions for the comparison to work correctly. Add an alt attribute to each image for accessibility.

Step by step

How to Use

  1. 1
    Drag the handleClick and drag the centre handle left and right to reveal the before (dark) and after (coloured) images.
  2. 2
    Replace with real imagesIn the HTML panel, replace the .before and .after div backgrounds with <img> tags or CSS background-image URLs.
  3. 3
    Change the initial splitIn the JS panel, call setPos(rect.left + rect.width * 0.5) on load to set any starting position.
  4. 4
    Change the handle styleUpdate .handle CSS: width, border colour, and the arrow icon SVG.
  5. 5
    Change the clamp rangeUpdate the Math.min(95, Math.max(5, ...)) values to allow a wider or narrower drag range.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Photo editing before/after showcase
Show the original and edited versions of a photo with the drag slider. Essential for photo retouching, colour grading, and restoration portfolios.
AI image enhancement demos
Demonstrate AI upscaling, noise reduction, or style transfer with a before/after slider. The interactive reveal is more compelling than two static images.
Website redesign comparisons
Show old vs new website design with the slider. Clients can drag to compare the original and redesigned versions side by side.
Learn clip-path reveal technique
The reveal uses clip-path: inset() which clips the element rect. Edit the setPos function to understand how clientX maps to a percentage and how the clip changes.
Product transformation showcases
Show before/after of a product process — raw material vs finished, unedited vs styled, dirty vs cleaned. The slider communicates transformation interactively.
Drop into any image-heavy page
Replace the placeholder divs with real img elements. The clip-path and handle logic is fully self-contained.
Related: Smartwatch Mockup
See the Smartwatch Mockup for a related layouts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

The .after image has clip-path: inset(0 X% 0 0). The inset values are top, right, bottom, left. Increasing right X% clips more of the right side, hiding the after image. Decreasing it reveals more. Moving the handle left increases the right clip; moving right decreases it.

setPos(x) computes pct = ((x - rect.left) / rect.width) * 100. rect.left is the container left edge. Dividing by rect.width normalises to 0-100. The result is clamped between 5 and 95 to keep the handle inside the container.

touchstart sets dragging = true. touchmove calls setPos(e.touches[0].clientX) — touches[0] is the first finger contact. This mirrors the mouse drag logic exactly.

Replace the .before and .after gradient backgrounds with background-image: url("your-before.jpg") and background-image: url("your-after.jpg") in the CSS. Or use <img> tags inside each div with position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover.

After the event listeners, call: const rect = compare.getBoundingClientRect(); setPos(rect.left + rect.width * 0.5); to start at 50%. Use 0.3 for 30% or 0.7 for 70%.

Yes. Click "JSX" for a React component. In React, use useRef on the container, after, and handle elements. Attach onMouseDown, onMouseMove, onMouseUp, onTouchStart, and onTouchMove to the container. Manage the dragging state in useRef (not useState) to avoid rerenders.