image compare before after slider comparison diff image compare before after slider split diff comparison overlay before after image comparison image diff slider
Image Comparer Base
Fetch pattern JSON:
curl https://webspire.de/patterns/image-comparer/base.json base.html
<style>
.ws-image-comparer input[type="range"] {
-webkit-appearance: none;
appearance: none;
background: transparent;
cursor: col-resize;
}
.ws-image-comparer input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 2.5rem;
height: 2.5rem;
border-radius: 9999px;
background: white;
border: 2px solid white;
box-shadow: 0 4px 12px rgba(0,0,0,0.25);
cursor: col-resize;
}
.ws-image-comparer input[type="range"]::-moz-range-thumb {
width: 2.5rem;
height: 2.5rem;
border-radius: 9999px;
background: white;
border: 2px solid white;
box-shadow: 0 4px 12px rgba(0,0,0,0.25);
cursor: col-resize;
}
.ws-image-comparer input[type="range"]::-webkit-slider-runnable-track {
height: 100%;
cursor: col-resize;
}
.ws-image-comparer input[type="range"]::-moz-range-track {
height: 100%;
cursor: col-resize;
}
</style>
<div class="ws-image-comparer relative mx-auto aspect-[16/9] w-full max-w-2xl overflow-hidden rounded-xl" style="--comparer-text: var(--ws-color-text);">
<!-- After image (background layer) -->
<div class="absolute inset-0 bg-gradient-to-br from-violet-400 to-indigo-600">
<span class="absolute right-3 top-3 rounded-full bg-black/50 px-3 py-1 text-xs font-medium text-white backdrop-blur-sm">After</span>
</div>
<!-- Before image (clipped layer — width controlled by range input) -->
<div class="absolute inset-0 bg-gradient-to-br from-amber-300 to-orange-500" id="comparer-before" style="clip-path: inset(0 50% 0 0)">
<span class="absolute left-3 top-3 rounded-full bg-black/50 px-3 py-1 text-xs font-medium text-white backdrop-blur-sm">Before</span>
</div>
<!-- Divider line — position follows the range input -->
<div class="absolute inset-y-0 w-0.5 bg-white/90 shadow-sm" id="comparer-line" style="left: 50%"></div>
<!-- Range input — invisible but interactive, drives the clip-path -->
<input type="range" min="0" max="100" value="50"
class="absolute inset-0 z-10 m-0 h-full w-full opacity-0"
aria-label="Slide to compare before and after"
oninput="
const v = this.value + '%';
this.parentElement.querySelector('#comparer-before').style.clipPath = 'inset(0 ' + (100 - this.value) + '% 0 0)';
this.parentElement.querySelector('#comparer-line').style.left = v;
this.parentElement.querySelector('#comparer-handle').style.left = v;
"/>
<!-- Visual handle (follows the range thumb) -->
<div class="pointer-events-none absolute top-1/2 flex h-10 w-10 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border-2 border-white bg-white/95 shadow-lg" id="comparer-handle" style="left: 50%">
<svg class="h-5 w-5 text-slate-700" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M8 7l-4 5 4 5M16 7l4 5-4 5"/>
</svg>
</div>
</div>
Details
Responsive Dark Mode Tailwind Only SSR Safe Copy & Paste
Stable Published
imagecomparebeforeafterslidercomparisondiff
Slots
| Name | Required | Description |
|---|---|---|
| before | Yes | Before image or content layer. |
| after | Yes | After image or content layer. |
| labels | No | Before/After label badges. |
Before/after image comparison with a vertical divider at 50%. The “before” layer uses clip-path: inset(0 50% 0 0) over the “after” layer. Corner labels and a centered drag handle with left/right arrows complete the visual. Static CSS-only preview — add JS for interactive dragging.