Free Webflow components / Effect: x-ray hover lens
Webflow x-ray hover effect (reveal lens)
A free x-ray hover effect for Webflow: a round lens follows the pointer and shows a second image underneath. Copy it, press ⌘V, and swap in your two images.
- JavaScript
- Responsive
What you receive in Webflow
- 15 native elements and 10 classes.
- Breakpoints: mobile landscape (767px), tablet (991px).
- 4 Embed elements keep the CSS or script that Webflow cannot express. To edit an Embed, you must have a paid Webflow site plan.
How to paste it
- Click Copy for Webflow.
- Open your page in the Webflow Designer.
- Press ⌘V or Ctrl+V.
HTML
<section class="xr">
<div class="xr-inner">
<div class="xr-copy">
<p class="xr-eyebrow">Inside the build</p>
<h2 class="xr-title">See what's under the surface</h2>
<p class="xr-text">Move over the object: a lens shows the blueprint underneath. Swap both layers for your product photo and its sketch.</p>
</div>
<div class="xr-stage" aria-label="Product with blueprint view on hover" role="img">
<div class="xr-layer xr-front">
<svg viewBox="0 0 400 400" width="100%" height="100%" aria-hidden="true">
<defs>
<linearGradient id="xrBody" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fde68a"></stop><stop offset="0.55" stop-color="#f59e0b"></stop><stop offset="1" stop-color="#b45309"></stop></linearGradient>
<radialGradient id="xrFace" cx="0.4" cy="0.35" r="0.75"><stop offset="0" stop-color="#1f2937"></stop><stop offset="1" stop-color="#030712"></stop></radialGradient>
</defs>
<rect x="160" y="20" width="80" height="80" rx="18" fill="#92400e"></rect>
<rect x="160" y="300" width="80" height="80" rx="18" fill="#92400e"></rect>
<circle cx="200" cy="200" r="130" fill="url(#xrBody)"></circle>
<circle cx="200" cy="200" r="108" fill="url(#xrFace)"></circle>
<rect x="326" y="186" width="22" height="28" rx="6" fill="#d97706"></rect>
<g stroke="#fbbf24" stroke-width="4" stroke-linecap="round"><path d="M200 112v16"></path><path d="M200 272v16"></path><path d="M112 200h16"></path><path d="M272 200h16"></path></g>
<path d="M200 200l46-34" stroke="#f9fafb" stroke-width="6" stroke-linecap="round"></path>
<path d="M200 200l-20 56" stroke="#f9fafb" stroke-width="4" stroke-linecap="round"></path>
<circle cx="200" cy="200" r="8" fill="#fbbf24"></circle>
</svg>
</div>
<div class="xr-layer xr-back">
<svg viewBox="0 0 400 400" width="100%" height="100%" aria-hidden="true">
<defs><pattern id="xrGrid" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M20 0H0V20" fill="none" stroke="#1e3a8a" stroke-width="1"></path></pattern></defs>
<rect width="400" height="400" fill="#0b1e4f"></rect>
<rect width="400" height="400" fill="url(#xrGrid)"></rect>
<g fill="none" stroke="#93c5fd" stroke-width="2">
<rect x="160" y="20" width="80" height="80" rx="18" stroke-dasharray="6 6"></rect>
<rect x="160" y="300" width="80" height="80" rx="18" stroke-dasharray="6 6"></rect>
<circle cx="200" cy="200" r="130"></circle><circle cx="200" cy="200" r="108"></circle>
<circle cx="200" cy="200" r="64" stroke-dasharray="4 8"></circle>
<circle cx="164" cy="176" r="22"></circle><circle cx="236" cy="230" r="30"></circle><circle cx="238" cy="160" r="14"></circle>
<path d="M70 200H40M360 200h-30M200 70V40M200 330v30"></path>
</g>
<g fill="#93c5fd" font-family="Arial, sans-serif" font-size="12"><text x="248" y="64">Ø 42 mm</text><text x="252" y="290">crown</text><text x="40" y="380">REV 3 · gear train</text></g>
</svg>
</div>
<div class="xr-ring" aria-hidden="true"></div>
</div>
</div>
</section>
<style>
.xr { font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; background: #111827; color: #f9fafb; padding: 112px 24px; }
.xr-inner { max-width: 1080px; margin: 0 auto; display: flex; align-items: center; gap: 64px; }
.xr-copy { flex: 1; }
.xr-eyebrow { font-size: 13px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: #fbbf24; margin: 0 0 16px; }
.xr-title { font-size: 48px; line-height: 1.08; letter-spacing: -0.03em; margin: 0 0 16px; }
.xr-text { font-size: 17px; line-height: 1.6; color: #9ca3af; margin: 0; max-width: 420px; }
.xr-stage { position: relative; flex: 0 0 440px; height: 440px; border-radius: 32px; overflow: hidden; background: #1f2937; cursor: none; touch-action: none; }
.xr-layer { position: absolute; top: 20px; right: 20px; bottom: 20px; left: 20px; }
.xr-back { -webkit-clip-path: circle(0px at var(--x, 50%) var(--y, 50%)); clip-path: circle(0px at var(--x, 50%) var(--y, 50%)); transition: clip-path 0.35s cubic-bezier(0.3, 0.9, 0.3, 1), -webkit-clip-path 0.35s cubic-bezier(0.3, 0.9, 0.3, 1); }
.xr-stage:hover .xr-back { -webkit-clip-path: circle(90px at var(--x, 50%) var(--y, 50%)); clip-path: circle(90px at var(--x, 50%) var(--y, 50%)); }
.xr-ring { position: absolute; left: var(--rx, 50%); top: var(--ry, 50%); width: 180px; height: 180px; margin: -90px 0 0 -90px; border-radius: 50%; border: 2px solid rgba(147, 197, 253, 0.9); box-shadow: 0 0 0 6px rgba(147, 197, 253, 0.15); opacity: 0; transform: scale(0.6); transition: opacity 0.25s ease, transform 0.35s ease; pointer-events: none; }
.xr-stage:hover .xr-ring { opacity: 1; transform: scale(1); }
@media (max-width: 991px) { .xr-inner { flex-direction: column; align-items: stretch; } .xr-stage { flex-basis: auto; width: 100%; max-width: 440px; margin: 0 auto; } }
@media (max-width: 767px) { .xr { padding: 80px 20px; } .xr-title { font-size: 34px; } .xr-stage { height: 340px; } }
</style>
<script>
document.querySelectorAll(".xr-stage").forEach(function (stage) {
function at(e) {
var r = stage.getBoundingClientRect();
var x = e.clientX - r.left, y = e.clientY - r.top;
stage.style.setProperty("--x", (x - 20) + "px");
stage.style.setProperty("--y", (y - 20) + "px");
stage.style.setProperty("--rx", x + "px");
stage.style.setProperty("--ry", y + "px");
}
stage.addEventListener("pointermove", at);
stage.addEventListener("pointerdown", function (e) { at(e); stage.classList.add("is-touch"); });
});
</script>
More examples
Questions
How do I use my own images?
Replace the two drawings (front and blueprint) with your own images of the same size. The lens shows the back layer wherever the pointer is.
Can I change the lens size?
Yes. The 90px radius is in the custom code Embed.
Is this effect component free?
Yes. Copy it with no account and use it on client sites and your own sites.
Does it work on the free Webflow plan?
Yes. It pastes on every Webflow plan, including Starter. If it includes an Embed element, editing that Embed's code needs a paid site plan.