Lightweight before / after image comparison slider. No dependencies, no canvas — built on a native <input type="range"> so the browser handles all pointer, touch, and keyboard interaction out of the box.
All visual state flows through a single CSS custom property (--compare-slider-pos), making the appearance fully overridable in CSS.
1. Markup — wrapper + two images:
<div class="compare-slider">
<img class="compare-slider__image" src="before.jpg" alt="Before" />
<img class="compare-slider__image compare-slider__after" src="after.jpg" alt="After" />
</div>2. Include styles and script:
<link rel="stylesheet" href="src/compare-slider.css" />
<script type="module">
import CompareSlider from './src/CompareSlider.js';
new CompareSlider('.compare-slider');
</script>3. Options (all optional):
new CompareSlider('.compare-slider', {
defaultValue: 30, // initial position (0–100), default: 50
prop: '--compare-slider-pos', // CSS custom property written on the wrapper
classes: {
input: 'compare-slider__input', // injected range input
handle: 'compare-slider__handle', // injected drag button
},
});| Method | Description |
|---|---|
setValue(n) |
Set position (0–100) on all matched instances |
destroy() |
Remove injected elements and restore initial state |
One selector initialises all matching elements at once:
const sliders = new CompareSlider('.compare-slider');
sliders.setValue(50); // syncs all instances
sliders.destroy();All visual state derives from --compare-slider-pos. Override any part in CSS:
/* Custom aspect ratio */
.compare-slider { aspect-ratio: 4 / 3; }
/* Custom divider colour */
.compare-slider::before { background: #6c63ff; }- Arrow keys move the slider (native
<input type="range">behaviour) - Focus ring on the handle via
:focus-within alttext on both images for screen readers