WebberUI

Zoom Lens

An image magnifier whose lens follows the cursor and magnifies in place, or presents the magnified result in a side panel.

Loading preview…
npx shadcn@latest add https://webberui.com/r/zoom-lens.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

2.5
160
<ZoomLens />

Installation

npx shadcn@latest add https://webberui.com/r/zoom-lens.json

Or, once registries are configured in components.json, install it as @webberui/zoom-lens.

Usage

import { ZoomLens } from "@/components/ui/zoom-lens";

<ZoomLens
  src="/product.jpg"
  alt="Product detail shot"
  className="w-full max-w-md"
/>

Side panel mode

The panel variant marks a viewfinder box on the original image and shows the magnified result in a side panel — a good fit for e-commerce product images.

<ZoomLens
  src="/product.jpg"
  alt="Product detail shot"
  variant="panel"
  panelPosition="right"
  zoom={2.6}
  size={200}
  className="w-64"
/>

Props

PropTypeDefaultDescription
srcstringImage source URL
altstring""Alternative text for the image
variant"lens" | "panel""lens"How the magnification is presented
zoomnumber2.5Magnification factor
sizenumber160Lens diameter (lens) / panel edge length (panel), in px
shape"circle" | "square""circle"Lens shape (lens only)
panelPosition"right" | "left" | "top" | "bottom""right"Panel position (panel only)
disabledbooleanfalseDisable the magnification interaction and show only the original image
onZoomChange(active: boolean) => voidCallback when the magnification on/off state changes
classNamestringclassName for the image frame; set the image size here
imageClassNamestringclassName for the <img>

How it works

  • Give a width in className (such as w-full max-w-md) and the image expands at its natural ratio with h-auto; the component measures the displayed size through a ResizeObserver and computes the magnified background from it.
  • The viewfinder's center is clamped inside the image's bounds, so the magnified content never exposes a blank edge.
  • The position follows smoothly via a Motion spring; lens and panel share the same background coordinate math, so the factor and size behave identically.
  • Mouse, touch, and stylus are all supported (Pointer Events); on touch you move the viewfinder by dragging, and it retracts when you let go.

Accessibility

  • The <img> keeps its alt, and the magnification interaction is progressive enhancement, so assistive technology still announces the image normally.
  • The lens, the viewfinder box, and the magnification panel are all decorative layers marked aria-hidden, so they do not interfere with the reading order.
  • When the user has "reduce motion" enabled at the system level, the tracking and the fade in/out land instantly, without using a spring or scaling.
  • The component cleans up its ResizeObserver, so no listeners are left behind on unmount.

On this page