Photo gridPro

Pinch through zoom levels and open any photo straight from its cell.

Live · keyboard ready

Desert weekend

16 photos2

Pinch, or hold Control and scroll, to zoom. Tap a photo to open it.

  • A browsable photo library or album where people zoom between column counts.
  • Galleries that need favorites and a full-screen viewer with a filmstrip.
  • Touch and trackpad users who expect pinch to change density.
  • Use lightbox-gallery for a masonry layout that keeps each photo's aspect ratio.
  • Use carousel for a short inline slideshow.
  • Use image-compare for before and after pairs.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { PhotoGrid, type GridPhoto } from "@/registry/components/photo-grid/photo-grid"; export function Album({ photos }: { photos: GridPhoto[] }) {  return (    <PhotoGrid      title="September"      photos={photos}      defaultColumns={4}      onFavoriteChange={(id, favorite) => saveFavorite(id, favorite)}    />  );}

PhotoGrid

A photo library grid with pinch or button zoom between column counts, favorites, and a full-screen viewer that grows from the tapped cell.

PropTypeDefaultDescription
photosRequired{ id: string; src: string; srcSet?: string; alt: string; width: number; height: number; title: string; detail?: string }[]–Photos in order. width and height are the intrinsic size; detail is a short line in the viewer, such as the date.
titleRequiredstring–Names the library, such as a month or album.
zoomLevelsnumber[][5, 3, 2]Column counts the zoom steps between.
defaultColumnsnumber3Initial column count.
onColumnsChange(columns: number) => void–Called when the zoom level changes.
defaultFavoritesstring[]–Ids favorited at mount.
onFavoriteChange(id: string, favorite: boolean) => void–Called when a photo is favorited or unfavorited.
onViewerChange(id: string | null) => void–Called with the photo id when the viewer opens and null as it starts to close.
classNamestring–Extra class on the root.
Arrow keys
Move focus between photos in the grid.
PageUporPageDownorHomeorEnd
Jump by three rows or to the first or last photo.
+or-
Zoom in or out a level around the focused photo.
EnterorSpace
Opens the focused photo in the viewer.
ArrowLeftorArrowRightorHomeorEnd
In the viewer, change photo.
Escape
Closes the viewer.
  • The grid is a labelled list of buttons named by each photo's alt text, with ", favorite" appended when favorited.
  • Zoom buttons use aria-pressed; the viewer is a labelled dialog and its filmstrip is a slider with the photo title in aria-valuetext.
  • Viewer changes are announced in a polite status region.
  • Pinch zoom scales live and reflows around the photo under the fingers; the viewer grows from the tapped cell and can be dragged down to dismiss.
  • Counters and favorite icons roll or pop in with a short blur.
  • Reduced motion removes layout travel and keeps fades.
  • Columns come from zoomLevels, not breakpoints; the root is a container and needs a height, with a 320px minimum.
  • Below 480px the header and filmstrip shrink, previous and next buttons hide, and swipe or the filmstrip pages instead.
  • Previous and next arrows are hidden on hover-less devices, where swipe is the main gesture.
  • The grid is not virtualized; every photo renders a thumbnail, so paginate very large libraries.
  • The viewer only mounts photos near the current one, and passing srcSet keeps thumbnails light.
  • The header and viewer use backdrop blur, which drops to solid surfaces under prefers-reduced-transparency.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose it for a browsable photo library or album. Use carousel for a short slideshow and image-compare for before/after.
  • Always pass width and height so the viewer and filmstrip can fit each photo without layout shift; pass srcSet for sharp thumbnails.

The full library index for assistants is at /llms.txt.