Image Loupe

Press Enter to magnify, then use the arrow keys to move, plus or minus to change the zoom and Escape to close.
About this component

Image Loupe

A magnifier for product and detail photos. In lens mode a round or rounded loupe follows the pointer and shows the picture under it at the chosen zoom; in side mode a pane opens beside the image and a box marks the area it shows, falling back to the lens when there is no room. The large file loads only on the first zoom, under the regular picture with a small spinner, then fades in. Scrolling changes the zoom while magnified. On touch, press and hold opens the lens above the finger so it is never covered, while a quick swipe still scrolls the page. The frame is a button: Enter magnifies, the arrow keys move, plus and minus zoom and Escape closes. Position and zoom reach the DOM as CSS variables, so moving costs no renders.

Usage

The import and the props worth knowing about, in one place.

import { ImageLoupe } from "@/components/beste/component/image-loupe";

<ImageLoupe
  src="https://images.unsplash.com/photo-1783676167814-13057079dd43?q=80&w=1200&auto=format&fit=crop"
  zoomSrc="https://images.unsplash.com/photo-1783676167814-13057079dd43?q=80&w=2400&auto=format&fit=crop"
  alt="Van Gogh, a wheat field with cypresses under swirling clouds"
  aspectRatio="4 / 3"
/>

<ImageLoupe
  src={product.image}
  zoomSrc={product.largeImage}   // fetched on the first zoom
  alt={product.name}
  mode="side"                    // "lens" (default) | "side"
  side="right"                   // pane on the right; the lens takes over without room
  defaultZoom={3}
  minZoom={1.5}
  maxZoom={6}
  wheelZoom={false}              // keep the wheel for scrolling
  lensShape="rounded"            // "circle" (default) | "rounded"
  lensSize={220}
  tone="outline"                 // "muted" (default) | "outline" | "ghost"
  size="lg"                      // "sm" | "default" | "lg"
  onZoomChange={(zoom) => console.log(zoom)}
/>

Keyboard and gestures

Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.

HoverThe lens follows the pointer; the wheel changes the zoom.
Press and holdOn touch, opens the lens above the finger. A quick swipe still scrolls.
EnterMagnifies from the keyboard; press again or Escape to close.
ArrowsMove the magnified area, Shift for fine steps.
+ / -Zoom in or out while magnified.

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
src*string—
alt*string—Required: the picture is the content, so it must be described.
zoomSrcstring—Larger file for the magnified view, fetched the first time someone zooms. Defaults to `src`.
mode"lens" | "side"—`lens` magnifies under the pointer; `side` opens a pane beside the image and marks the area it shows.
side"right" | "left"—Which side the pane opens on in `side` mode. Falls back to the lens when there is no room.
zoomnumber—
defaultZoomnumber—
onZoomChange(zoom: number) => void—
minZoomnumber—
maxZoomnumber—
wheelZoomboolean—Scrolling over the image changes the zoom while it is magnified.
lensShape"circle" | "rounded"—
lensSizenumber—Lens diameter in px. Defaults by `size`.
aspectRatiostring—CSS aspect ratio of the frame. The picture covers it.
hintstring—Hint in the corner. Set to an empty string to hide it.
disabledboolean—
size"sm" | "default" | "lg"—
tone"muted" | "outline" | "ghost"—
classNamestring—

More Loupe components

View all Loupe
Wheat field with cypresses, restored to full colorWheat field with cypresses, as an archive print