Image Gallery
<x-wirekit::image-gallery> lays out user-content images in a responsive grid.
Clicking a thumbnail opens an accessible lightbox — a focus-trapped dialog
that navigates with the arrow keys, closes on Escape, and returns focus to the
thumbnail you opened it from. Each image is a <x-wirekit::image>
figure, so alt text, lazy loading, and a CLS-safe ratio box come for free.
Pass an array of images, each with a src and an alt (and an optional
caption). A signed, ACL-protected download URL works unchanged.
Usage
Columns and ratio
Control the responsive grid with columns (forwarded to the grid) and the
thumbnail shape with ratio:
Static grid (no lightbox)
Set :lightbox="false" for a plain responsive grid of figures — no dialog, no
JavaScript:
Per-Item Overlays
Pass an itemOverlay closure to layer a control over each thumbnail — a badge, a
per-image report button, or a required content label (a synthetic-media disclosure,
a license marker). The closure receives ($item, $i) and returns the markup; it renders as a
sibling of the zoom trigger, not inside it, so the thumbnail still opens the
lightbox. The overlay wrapper is pointer-events-none — give any interactive control
inside it pointer-events: auto so it stays clickable without triggering the zoom.
Return a view or an HtmlString for HTML (a plain string is escaped):
In real code the closure typically returns a partial view so the overlay can carry its own components and logic:
<x-wirekit::image-gallery
:images="$photos"
:item-overlay="fn (array $item, int $i) => view('partials.photo-report', ['photo' => $item, 'index' => $i])"
/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
images |
array |
[] |
List of images — each an array with src, alt, and optional caption. A plain string is treated as a decorative src. |
columns |
string |
'2 md:3 lg:4' |
Responsive grid column spec (forwarded to the grid). |
gap |
string |
'md' |
Grid gap token. |
ratio |
string|null |
'1/1' |
Thumbnail aspect-ratio (CLS-safe). |
fit |
string |
'cover' |
object-fit for each thumbnail. 'cover' crops to a uniform grid (right for mixed-orientation sets); 'contain' shows each image whole, letterboxed inside its ratio box — use it when a single portrait shot must not be cropped. |
lightbox |
bool |
true |
Enable the click-to-zoom lightbox. false renders a static grid. |
itemOverlay |
Closure|null |
null |
Per-item overlay render-callback fn($item, $i). Returns markup layered over thumbnail $i as a sibling of the zoom trigger — a badge, a report control, a synthetic-media label. Return a view or HtmlString for HTML. See Per-Item Overlays. |
scope |
string|null |
null |
Scoped personalization key. |
Accessibility
- Each thumbnail is a real
<button>with an accessible name ("View image 2: …"), so the gallery is fully keyboard-operable. - The lightbox is a
role="dialog"aria-modal="true"overlay, focus-trapped with the same helper Modal and Drawer use — focus cannot escape to the page behind it, and it returns to the triggering thumbnail on close. - Every image carries its
alt; decorative images passalt="".
Keyboard Interaction
| Key | Action |
|---|---|
Enter / Space |
Open the lightbox on the focused thumbnail |
Escape |
Close the lightbox (focus returns to the thumbnail) |
← |
Previous image |
→ |
Next image |
Tab |
Move between the lightbox controls (focus stays trapped inside) |