Create a two-column hero with Tailwind CSS: marketing copy on the left, an interactive before/after comparison on the right. The copy column has an eyebrow, a tight headline, a supporting paragraph, a dark CTA plus a ghost secondary button, and a small line of proof. The comparison column is a relative 4:3 rounded panel with overflow-hidden and select-none. Inside it, layer a polished "after" mock on neutral-900 (a header row, a chart block, three metric tiles) as the base, then an absolutely positioned "before" layer clipped by its own width holding a drab neutral-100 version of the same mock; each layer carries its own small corner label. Over both, a full-height drag handle: a thin white rule with a round shadowed grip, positioned by inline left percentage, and reachable by keyboard as a button. Then add JavaScript that sizes the inner "before" mock to the panel width so it never reflows while clipped, updates the clip width and handle position from pointer events while dragging (pointer capture so the drag survives leaving the panel), moves the divider 5% per arrow-key press when the grip is focused, clamps the value between 0 and 100, and re-measures on resize.
Paste it into Claude, Cursor, v0 or any AI coding tool. Prefer the
finished markup? .
Create a two-column hero with Tailwind CSS: marketing copy on the left, an interactive before/after comparison on the right. The copy column has an eyebrow, a tight headline, a supporting paragraph, a dark CTA plus a ghost secondary button, and a small line of proof. The comparison column is a relative 4:3 rounded panel with overflow-hidden and select-none. Inside it, layer a polished "after" mock on neutral-900 (a header row, a chart block, three metric tiles) as the base, then an absolutely positioned "before" layer clipped by its own width holding a drab neutral-100 version of the same mock; each layer carries its own small corner label. Over both, a full-height drag handle: a thin white rule with a round shadowed grip, positioned by inline left percentage, and reachable by keyboard as a button. Then add JavaScript that sizes the inner "before" mock to the panel width so it never reflows while clipped, updates the clip width and handle position from pointer events while dragging (pointer capture so the drag survives leaving the panel), moves the divider 5% per arrow-key press when the grip is focused, clamps the value between 0 and 100, and re-measures on resize.
var panel = document.getElementById("compare");
var beforeLayer = document.getElementById("beforeLayer");
var beforeInner = document.getElementById("beforeInner");
var handle = document.getElementById("handle");
var position = 50;
function render() {
beforeLayer.style.width = position + "%";
handle.style.left = position + "%";
}
// The clipped mock must keep the panel's full width, or its contents reflow as it narrows.
function measure() {
beforeInner.style.width = panel.clientWidth + "px";
render();
}
function moveTo(clientX) {
var box = panel.getBoundingClientRect();
position = Math.min(100, Math.max(0, ((clientX - box.left) / box.width) * 100));
render();
}
panel.addEventListener("pointerdown", function (e) {
panel.setPointerCapture(e.pointerId);
moveTo(e.clientX);
});
panel.addEventListener("pointermove", function (e) {
// Buttons is a bitmask — 1 means the primary button is still held.
if (e.buttons & 1) moveTo(e.clientX);
});
handle.addEventListener("keydown", function (e) {
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
e.preventDefault();
position = Math.min(100, Math.max(0, position + (e.key === "ArrowRight" ? 5 : -5)));
render();
});
window.addEventListener("resize", measure);
measure();