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.