A lightweight lightbox,
in a single file.
Zoom, pan, touch gestures, keyboard navigation, accessible labels — all packed into one dependency-free JavaScript file. CSS inlined, no build step, framework-agnostic.
Quick start
Add the script, bind a selector, done.
<!-- Include (or download and self-host) --> <script src="https://litezoom.dev/litezoom.min.js" defer></script> <!-- Bind: article images open on click; full mode adds zoom / pan / thumbnails --> <script> LiteZoom.bind('.post-content img', { mode: 'full' }); </script>
https://litezoom.dev/litezoom.min.js
Demo
This page uses LiteZoom itself — click any image. Scroll or pinch to zoom, drag to pan, pull down to close.
Keyboard: Esc close · ← → switch · + − zoom · double-click toggles 1x / 2x
Why LiteZoom
Trade-offs made for content sites, not a feature contest.
Single-file delivery
CSS inlined, SVG icons inline. No build chain, no peer dependencies — copy one file into any project and it works.
Two modes
simple just opens and switches, great for feeds; full adds zoom, pan, a thumbnail strip and captions for long-form articles.
Full gestures
Wheel and pinch zoom, drag to pan, swipe to switch, pull down to close — one Pointer Events implementation for desktop and touch.
Accessibility done right
Focus returns to the trigger on close; every aria label is localizable; respects prefers-reduced-motion.
Never hijacks real links
Images wrapped in links to other pages navigate as usual; links to large images load the hi-res original. Use data-litezoom for extension-less URLs.
Lazy-load enhancer
Ships enhance(): IntersectionObserver lazy loading + blur-in fade, sharing a single binding with the lightbox.
API
| Method | Description |
|---|---|
LiteZoom.bind(sel, opts) | Delegated binding: images matching sel open on click. opts.mode is 'simple' | 'full'; group(img) returns a group key for gallery navigation; caption(img) returns the caption; exclude(img) returns true to skip. |
LiteZoom.open(items, i, opts) | Open manually: items is an array of {src, thumb?, caption?}, i the start index. For React / Vue apps that handle clicks themselves. |
LiteZoom.close() | Close the current lightbox. |
LiteZoom.enhance(sel, opts) | Image enhancement: lazy loading (data-src) with blur-in fade; set opts.zoom to true to also bind the lightbox. |
LiteZoom.refresh(root) | Re-apply enhancement to images inserted dynamically. |
data-litezoom | Explicit marker, takes priority over the extension heuristic: on an <a> it means "the href is an image, open the lightbox" (for extension-less CDN URLs); as <img data-litezoom="hi-res URL"> it names the hi-res source directly, no wrapping link needed. |
LiteZoom.labels(map) | Override accessibility labels (Chinese by default): {viewer, prev, next, zoomIn, zoomOut, close, thumb(i)}. |