Image Zoom
InteractiveA hover/press inner-zoom magnifier whose magnified region tracks the pointer inside the image (no lens box), paired with a click-to-open full-screen lightbox that portals to the body with a blurred backdrop, Escape/backdrop-click close, focus trap, and focus return. Under prefers-reduced-motion the zoom-follow is dropped (the static image stays fully legible) and the lightbox opens instantly.
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/image-zoom.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/image-zoom.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div className="flex w-full items-center justify-center p-6">
<ImageZoom
className="w-[300px] max-w-full shadow-[0_24px_60px_-30px_rgba(0,0,0,0.9)]"
zoom={2.6}
alt="Parable poster — the number 42 inside concentric rings, hover to magnify"
src={"data:image/svg+xml," + encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 480'><defs><linearGradient id='g' x1='0' y1='0' x2='1' y2='1'><stop offset='0' stop-color='#8b5cf6'/><stop offset='.5' stop-color='#ec4899'/><stop offset='1' stop-color='#f5a623'/></linearGradient><radialGradient id='v' cx='.5' cy='.42' r='.72'><stop offset='0' stop-color='#0f0f10' stop-opacity='0'/><stop offset='1' stop-color='#0f0f10' stop-opacity='.55'/></radialGradient></defs><rect width='640' height='480' fill='#0f0f10'/><rect width='640' height='480' fill='url(#g)' opacity='.92'/><circle cx='320' cy='202' r='120' fill='#0f0f10' fill-opacity='.28'/><circle cx='320' cy='202' r='120' fill='none' stroke='#fff' stroke-opacity='.5' stroke-width='2'/><circle cx='320' cy='202' r='80' fill='none' stroke='#fff' stroke-opacity='.35' stroke-width='1.5'/><text x='320' y='224' font-family='ui-monospace,Menlo,monospace' font-size='76' font-weight='700' fill='#fff' text-anchor='middle'>42</text><text x='320' y='356' font-family='ui-monospace,Menlo,monospace' font-size='27' letter-spacing='9' fill='#fff' fill-opacity='.92' text-anchor='middle'>PARABLE</text><text x='320' y='390' font-family='ui-monospace,Menlo,monospace' font-size='12' letter-spacing='3' fill='#fff' fill-opacity='.6' text-anchor='middle'>HOVER TO MAGNIFY</text><rect x='.5' y='.5' width='639' height='479' fill='url(#v)'/></svg>`)}
/>
</div>Props
ImageZoomProps
| Prop | Type | Default | Description |
|---|---|---|---|
| src* | string | — | Image source. Used for both the inline frame and the lightbox. |
| alt* | string | — | Alt text (required). Also names the lightbox dialog for assistive tech. |
| zoom | number | 2 | Inner-zoom magnification while hovering/pressing the frame. Default `2`. |
| lightbox | boolean | true | Whether clicking the frame opens the full-screen lightbox. Default `true`. |
| width | number | — | Intrinsic pixel width — set with `height` to reserve space (no CLS). |
| height | number | — | Intrinsic pixel height — set with `width` to reserve space (no CLS). |
| className | string | — | Extra classes on the frame element. |
npm dependencies
- motion
- lucide-react