Gallery grid

Lays out an image collection as an even grid, masonry columns or justified rows, opens items in the Lightbox, and has an edit mode for listings and gallery blocks: reorder by drag or keyboard (with a Move menu as the non-drag alternative), remove, caption and add.

Own layout math (deterministic, SSR-safe) · Sortable for edit mode media/gallery.tsx, media/gallery-layout.tstheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { Gallery } from "@vamos-ui/react/media";

<Gallery items={photos} layout="masonry" columns={{ base: 2, md: 3 }} lightbox />

Tiles never get backdrop-filter. The hover layer uses --overlay; selection and focus use --ring.

In view mode an empty gallery renders nothing; in edit mode it shows the Add tile.

Examples

Masonry

Items go to the shortest column by their known ratio, so the layout is the same on the server and the client.

Justified rows

Equal-height rows that fill the width exactly; the last row keeps the target height. A proportional flex layout renders before the first measurement.

Captions

below renders a <figcaption>; overlay paints it on a scrim at the bottom of the tile.

Edit mode

Drag by the handle or press Space, arrows, Space. Each tile also has a Move menu (WCAG 2.5.7), Remove, and an inline caption. onAdd opens your Media picker.

Responsive columns (team page)

columns follows the gallery's own width (container queries), so it works the same in a sidebar or full width.

API

Gallery

PropTypeDefault
items
Assets or plain { src, alt, width, height, caption }. width/height drive masonry and justified layouts.
(MediaAsset | MediaSource)[]—
layout
Even tiles, columns by ratio, or equal-height rows.
"grid" | "masonry" | "justified""grid"
columns
Columns for grid and masonry, by container width.
number | { base?, sm?, md?, lg? }{ base: 2, sm: 3, lg: 4 }
aspect
Tile ratio in the grid layout and edit mode.
ImageAspect"1/1"
rowHeight
Target row height in px (justified).
number220
captions
Where captions show.
"none" | "below" | "overlay""none"
gap
6 / 12 / 20 px between tiles.
"sm" | "md" | "lg""md"
rounded
Tile corners.
"none" | "ui" | "ui-lg""ui"
lightbox
Tiles become "Enlarge image: {alt}" buttons that open the Lightbox; pass an object for its options.
boolean | LightboxProps (without items)false
sizes
sizes for every image. Default derived from the column count.
string—
loading / skeletonCount
Skeleton tiles that keep their ratio.
boolean / numberfalse / 6
label
Accessible name of the list.
string"Gallery"
editable
Edit mode (grid layout): handle drag + keyboard reorder, Move menu, Remove, caption input, Add tile.
booleanfalse
onReorder
New order of item ids. Without it the items can't be moved.
(ids: string[]) => void—
onRemove
Shows a Remove button per tile.
(id: string) => void—
onCaptionChange
Shows an inline caption field (commits on blur / Enter).
(id: string, caption: string) => void—
onAdd
"Add images" tile (a large drop-style tile when the gallery is empty).
() => void—
labels
enlarge, remove, caption, add… (dictionary namespace gallery).
Partial<GalleryLabels>—

Layout helpers

PropTypeDefault
masonryColumns(ratios, columns)
Item indexes per column, shortest column first.
→ number[][]—
justifyRows(ratios, width, rowHeight, gap?)
Flickr-style rows.
→ { items, height, justified }[]—