← The library

Compare slider

A before/after handle to reveal two images

Free

What's included

A before/after slider, in two files: a stylesheet and a script. No dependencies, no build step, no external requests — you copy them into a project and it works. The two demo images come with it.

The component doesn't reinvent a slider: it sits on a browser <input type="range">, stretched across the whole image and painted transparent. That's what receives the finger, the mouse and the keyboard; that's what carries the sliderrole, its bounds and its value for screen readers. The script adds one thing only: it copies that value into a CSS variable.

Features

  • Full keyboard support, without a line of code — arrows, Page Up and Page Down, Home and End: it all comes from the native slider, so nothing can drift out of step with the platform.
  • Vertical direction — one class is enough. It's the browser that turns the control: the gesture, the arrow keys and the announced orientation all follow by themselves.
  • The two images stay aligned — the reveal is a clip, not a resize. No position, not even 1%, shifts them out of register.
  • It tightens up according to the room it gets — not according to the size of the screen. Dropped into a narrow column on a wide page, it still reduces its spacing.
  • One variable for the scale — frame, corner radius, handle, chevrons and labels all derive from the text size and follow together.
  • The page keeps scrolling — on mobile, the component takes the horizontal gesture and leaves the vertical one to a finger that simply wants to scroll.

Dropping it into a page

Two files to load, then the markup:

<link rel="stylesheet" href="compare-slider.css">
<script src="compare-slider.js" defer></script>
<div class="compare-slider">
 <div class="compare-slider__frame">
  <img class="compare-slider__image"
       src="apres.webp" alt="After">
  <div class="compare-slider__reveal">
   <img class="compare-slider__image"
        src="avant.webp" alt="Before">
  </div>
  <span class="compare-slider__label
               compare-slider__label--before">Before</span>
  <span class="compare-slider__label
               compare-slider__label--after">After</span>
  <span class="compare-slider__line" aria-hidden="true"></span>
  <span class="compare-slider__handle" aria-hidden="true">
   <svg class="compare-slider__handle-icon"
        viewBox="0 0 24 24" aria-hidden="true">
    <path d="M9 6 L4 12 L9 18 M15 6 L20 12 L15 18"/>
   </svg>
  </span>
  <input class="compare-slider__control" type="range"
         min="0" max="100" step="any" value="50"
         aria-label="Comparison position">
 </div>
</div>

No attribute to remember: the component installs itself on page load on every .compare-slider, including those added later. Add the compare-slider--vertical class for the vertical direction, compare-slider--paper for the light background.

What you should know

  • Without JavaScript, it appears but no longer moves. The two images, the labels and the seam all stay there, at the position set in CSS. The slider itself is removed: there's no way to tie a range to a CSS variable without a script, and a control that moves without moving anything is worth less than no control at all.
  • The stage wants a height. By default it takes the reference's own; give it --cs-block-size: 100% so it fills its parent, provided that parent has one.
  • No inline styles, no inline scripts. The component honours the site's strict security policy, and never uses innerHTML.
  • The design comes from elsewhere. The proportions follow those of a commercial Framer component, measured on the published site at five widths. The code itself is original — the technique isn't even the same — and the two photographs, a room before and after renovation, were generated for this folder.

Take it, open it, break it.

This component is free. The full library — the templates and the other components — comes with the subscription, alongside the course.

Immediate access · No commitment · Cancel in one click