image-gallery
Thumbnail grid with lightbox viewer. Progressively enhances linked thumbnails into a fullscreen gallery with navigation, swipe, keyboard support, and View Transitions.
Overview
A thumbnail grid that opens a fullscreen lightbox viewer on click. Progressive enhancement at every layer: without JS, thumbnails are plain links to full images. With JS, a native <dialog> lightbox adds navigation, swipe, keyboard control, and View Transitions.
Uses the Invokers API (commandfor/command) for declarative close, and the Popover API (popovertarget) for caption details.
Usage
Image-only
Wrap each thumbnail in an <a> linking to the full image. The href is the full-size source; the <img> is the thumbnail.
<image-gallery> <a href="photos/full-1.jpg"> <img src="photos/thumb-1.jpg" alt="Mountain landscape" loading="lazy" /> </a> <a href="photos/full-2.jpg"> <img src="photos/thumb-2.jpg" alt="Ocean sunset" loading="lazy" /> </a></image-gallery>
With Captions
Wrap each item in a <figure> with a <figcaption>. Captions support HTML including links, and display in the lightbox via a popover panel.
<image-gallery> <figure> <a href="photos/full-1.jpg"> <img src="photos/thumb-1.jpg" alt="Mountain landscape" loading="lazy" /> </a> <figcaption> <strong>Sunrise over the Alps</strong> <p>Taken in Zermatt. <a href="/gallery/alps">View series</a></p> </figcaption> </figure></image-gallery>
Progressive Enhancement
| Layer | What works |
|---|---|
| HTML only | Grid of linked images; click navigates to full image |
| HTML + CSS | Responsive auto-fit grid, aspect-ratio thumbnails, hover zoom |
| + Invokers | Dialog close button works declaratively |
| + JS | Lightbox opens, navigation, keyboard, swipe, counter |
| + View Transitions | Thumbnail morphs into full image |
Grid Configuration
Control the thumbnail grid layout with columns, gap, and ratio attributes.
<image-gallery columns="150px" gap="xs" ratio="16:9"> <a href="wide-1.jpg"><img src="thumb-1.jpg" alt="..." loading="lazy" /></a> <a href="wide-2.jpg"><img src="thumb-2.jpg" alt="..." loading="lazy" /></a></image-gallery>
Lightbox Navigation
- Prev/Next buttons in the lightbox header
- Keyboard: ArrowLeft/Right, Home/End, Escape to close
- Swipe: Left/right touch gestures on the image area
- Loop: Add
loopattribute to wrap at ends
Counter displays "X of Y" and is announced to screen readers via aria-live.
Caption Modes
The captions attribute controls how <figcaption> content appears in the lightbox.
| Value | Behavior |
|---|---|
auto (default) | Info button in header; toggles a popover panel via popovertarget |
overlay | Persistent caption bar below the image |
hidden | Captions suppressed in lightbox (still visible in grid) |
Accessibility
- Native
<dialog>provides focus trapping, Escape-to-close, and::backdrop - Close button uses
commandfor/command="close"(Invokers API) - Counter uses
aria-live="polite"for screen reader announcements - Prev/Next buttons have
aria-labelanddisabledstate at boundaries - All animations respect
prefers-reduced-motion