Before-and-after sliders are one of the most effective ways to showcase transformations. Whether you are a photographer, interior designer, dentist, contractor, or fitness coach, a visual comparison tells a story that words alone cannot. Squarespace does not offer this as a native block, but you can add one with clean, lightweight code.
How Before-After Sliders Work
Two images are stacked on top of each other. A clip-path or overflow-hidden technique reveals only a portion of the top image, and a draggable handle lets the user control how much of each image is visible.
Step 1: Prepare Your Images
Both images must have identical dimensions. If your before photo is 1200 by 800 pixels, your after photo must also be 1200 by 800. Any mismatch in aspect ratio will cause misalignment.
Compress both images to under 300KB each. The slider loads both images at full resolution, so unoptimized images will double your typical image load time for that section.
Step 2: The HTML Structure
<!-- Paste into a Code Block (HTML mode) -->
<div class="ba-slider" style="--position: 50%">
<img src="/s/before.jpg" alt="Kitchen before renovation
— dark cabinets, outdated countertops" class="ba-before">
<img src="/s/after.jpg" alt="Kitchen after renovation
— white quartz counters, pendant lights" class="ba-after">
<div class="ba-handle">
<div class="ba-handle-line"></div>
<div class="ba-handle-circle">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="#fff" stroke-width="2">
<path d="M8 4l-6 8 6 8M16 4l6 8-6 8"/>
</svg>
</div>
<div class="ba-handle-line"></div>
</div>
<span class="ba-label ba-label-before">Before</span>
<span class="ba-label ba-label-after">After</span>
</div>Step 3: The CSS
.ba-slider {
position: relative;
overflow: hidden;
cursor: col-resize;
aspect-ratio: 3/2;
border-radius: 8px;
}
.ba-slider img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.ba-after {
clip-path: inset(0 0 0 var(--position));
}
.ba-handle {
position: absolute;
top: 0;
bottom: 0;
left: var(--position);
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
z-index: 2;
}
.ba-handle-line {
flex: 1;
width: 3px;
background: #fff;
box-shadow: 0 0 4px rgba(0,0,0,0.3);
}
.ba-handle-circle {
width: 40px;
height: 40px;
border-radius: 50%;
background: #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.ba-label {
position: absolute;
bottom: 16px;
font-size: 11px;
font-weight: 600;
letter-spacing: 1.5px;
text-transform: uppercase;
color: #fff;
background: rgba(0,0,0,0.5);
padding: 6px 12px;
border-radius: 4px;
}
.ba-label-before { left: 16px; }
.ba-label-after { right: 16px; }Step 4: The JavaScript
<script>
document.querySelectorAll('.ba-slider').forEach(slider => {
let isDragging = false;
function updatePosition(x) {
const rect = slider.getBoundingClientRect();
const pos = Math.max(0, Math.min(1,
(x - rect.left) / rect.width));
slider.style.setProperty('--position', pos * 100 + '%');
}
slider.addEventListener('mousedown', () => isDragging = true);
document.addEventListener('mouseup', () => isDragging = false);
document.addEventListener('mousemove', e => {
if (isDragging) updatePosition(e.clientX);
});
// Touch support
slider.addEventListener('touchstart', () => isDragging = true);
document.addEventListener('touchend', () => isDragging = false);
slider.addEventListener('touchmove', e => {
updatePosition(e.touches[0].clientX);
});
// Keyboard support
slider.setAttribute('tabindex', '0');
slider.setAttribute('role', 'slider');
slider.addEventListener('keydown', e => {
const current = parseFloat(
slider.style.getPropertyValue('--position')) || 50;
if (e.key === 'ArrowLeft') {
slider.style.setProperty('--position',
Math.max(0, current - 5) + '%');
} else if (e.key === 'ArrowRight') {
slider.style.setProperty('--position',
Math.min(100, current + 5) + '%');
}
});
});
</script>Use Our Generator Instead
Our Before and After Slider Generator handles all of this. Upload your two images, choose a handle style, set the starting position, and copy the generated code. It outputs production-ready code with all the accessibility attributes, touch support, keyboard navigation, and responsive behavior already built in.
