Avara UI

Gallery & Lightbox

A photo gallery is really two problems, and they are best solved by two libraries. react-photo-album handles layout — fitting uneven aspect ratios into rows or columns without cropping anything — and yet-another-react-lightbox handles the viewer: keyboard navigation, pinch zoom, captions, thumbnails, fullscreen and slideshow.
Neither owns the page chrome, so the whole gallery drops inside a Card unchanged.

Rows layout

Justified rows with captions

Click any photo to open it. Arrow keys move, Escape closes, the counter and thumbnail strip come from plugins — and the card around it all is Algorize UI.

Give every photo awidth
and height. The album computes its layout from the aspect ratio before the images load — omit them and the rows reflow as each one arrives.
srcSet
is what keeps a grid of 1600px originals from being downloaded at full size. The album picks the right entry for the rendered width.
targetRowHeight
is a target, not a rule — the last row and narrow viewports both bend it to avoid cropping.
slides
on the lightbox accepts the same array, so title and description on a photo become the caption with no second data shape.

Installation

npm install react-photo-album yet-another-react-lightbox
This example also uses these Algorize UI components — install whichever your project does not already have:
npx shadcn@latest add @algorize-ui/card

Masonry layout

The same two libraries in a different arrangement: MasonryPhotoAlbum packs uneven heights into columns, and the lightbox is opened from a hover affordance rather than the whole tile — so the overlay button is yours while the album's own image element stays untouched.

Masonry columns with a hover control

Column count responds to the container, not the viewport. Fullscreen, slideshow, zoom and download are four plugin imports.

Passcolumns
a function of the container width. Reading the container rather than the viewport is what keeps the album correct inside a sidebar or a modal.
render.extras
layers your own markup over a tile without replacing the image element — the hover overlay here.
componentsProps.button
puts group relative on the tile's own button, which is what lets group-hover drive that overlay.
plugins
are additive and each ships its own CSS where it needs it — captions.css, counter.css, thumbnails.css. Zoom and fullscreen need none.

Installation

Same two packages as above — MasonryPhotoAlbum and the extra plugins ship inside them, so there is nothing new to add:
npm install react-photo-album yet-another-react-lightbox
npx shadcn@latest add @algorize-ui/card

The layouts and the plugins

react-photo-album exports three album components, all taking the same photo array:
ComponentArrangementGood for
RowsPhotoAlbumJustified rows of equal heightMixed landscape and portrait, editorial feel
ColumnsPhotoAlbumFixed columns, photos in orderReading order matters
MasonryPhotoAlbumColumns balanced by heightTall and wide mixed, no gaps
The lightbox is plugin-based, and each plugin is opt-in:
PluginAddsExtra CSS
CaptionsTitle and description overlaycaptions.css
Counter"3 / 12" positioncounter.css
ThumbnailsFilmstripthumbnails.css
ZoomPinch and wheel zoom—
FullscreenFullscreen API—
SlideshowTimed auto-advance—
DownloadSave the original—
VideoVideo slides alongside photos—

Notes

Theming the viewer. The lightbox reads its own CSS variables, adapting automatically to light and dark modes with a translucent, blurred frosted-glass backdrop (backdrop-filter: blur(16px)).
Server rendering. The lightbox renders nothing until open is true, so it is safe anywhere. The album has a dedicated react-photo-album/ssr entry point for server-rendered layout if the first paint matters to you.
Next.js images. Both examples use a plain <img> so the code runs unchanged in any React app. To route through next/image, pass a custom image renderer via the album's render.image — the layout maths is unaffected.