← Back to site

ImageGrid

The ImageGrid component arranges a list of images in a responsive grid. It has two layout modes — a square 1:1 CSS Grid and a native-aspect masonry built on CSS columns — and delegates the actual image rendering to <Img>, so every tile gets the same srcset, lazy-loading, and click-to-enlarge behaviour as a standalone image.

It lives under src/components/reusable/ rather than src/components/mdx/, but is re-exported from the @mdx barrel so it can be used inside MDX content alongside the other components.

Import

import ImageGrid from '@mdx/ImageGrid.astro';
// or, equivalently:
import ImageGrid from '@reusable/ImageGrid.astro';

Props

PropTypeDefaultDescription
imagesImageWithAlt[]Required. Array of { image, alt, description? } entries; image is an ImageMetadata import. When description is set, a gradient strip renders on the bottom of that image (and beneath it in the click-to-enlarge modal). Use description for any combination of caption and photographer credit — there’s no separate copyright field.
cols2 | 3 | 4 | 5 | 64Desktop column count (mobile is always 2 cols)
gap'sm' | 'md' | 'lg''md'Spacing between tiles
aspectRatio'square' | 'native''square'square crops to 1:1, native keeps original aspect ratios in a masonry layout
enableClickToEnlargebooleantrueForwarded to every <Img> inside the grid
classstringExtra classes for the grid container

ImageWithAlt is defined in @types:

interface ImageWithAlt {
  image: ImageMetadata | string;
  alt: string;
  description?: string;
}

description is optional. When set, the image renders a tight gradient strip at the bottom showing the description text. The same text shows beneath the enlarged image inside the click-to-enlarge modal. Use description for any combination of caption and photographer credit.

Layout Modes

Square (CSS Grid)

aspectRatio="square" (default) renders a display: grid container. Each tile is wrapped in a <div class="square-grid-item"> whose CSS aspect-ratio: 1 / 1 forces a 1:1 box; the inner <Img> uses object-fit: cover and object-position: center to crop. This mode produces a perfectly aligned grid — same row heights, same column widths.

Column classes (responsive):

colsMobilelg: (≥1024 px)
2grid-cols-2grid-cols-2
3grid-cols-2grid-cols-3
4grid-cols-2grid-cols-4
5grid-cols-2grid-cols-5
6grid-cols-2grid-cols-6

Native (CSS columns / masonry)

aspectRatio="native" switches to display: block with column-count (columns-2 lg:columns-4 etc.). Each tile uses break-inside: avoid so it never splits across columns, and margin-bottom provides vertical spacing. Images keep their original aspect ratios — no cropping — and the layout flows Pinterest-style, with shorter tiles tucked under taller ones.

This mode is purely CSS — no JavaScript layout code — which means the visual order of items follows column-fill order, not source order (browser default is column-fill: balance). For galleries this is usually fine; for ordered content prefer the square mode.

Sizes Hint

The component computes a sizes value from cols and passes it to each <Img>:

colssizes value
2"50vw"
3"(min-width: 1024px) 33vw, 50vw"
4"(min-width: 1024px) 25vw, 50vw"
5"(min-width: 1024px) 20vw, 50vw"
6"(min-width: 1024px) 17vw, 50vw"

This lets the browser pick the smallest image from the srcset that still covers the rendered tile.

Lazy Loading

The first cols * 2 images load eagerly (i.e. the visible-on-load top section — two full rows in square mode); everything below is lazy. This keeps the first paint snappy without loading the entire gallery up front.

Spacing Between Tiles

gapSquare mode (gap-*)Native mode (mb-*)
smgap-2mb-2
mdgap-3 lg:gap-4mb-3 lg:mb-4
lggap-4 lg:gap-6mb-4 lg:mb-6

Square mode uses CSS Grid gap (both axes); native mode uses margin-bottom per item (CSS columns ignores gap between items, only between columns).

CMS Behaviour

When ImageGrid is inserted via the Keystatic MDX editor, each image entry is a direct file upload — the editor writes the resulting filename into images[].image and Keystatic stores the file under the surrounding entry’s per-slug asset folder. This is why the schema accepts images as an inline array rather than a folder reference: it lets editors add images one at a time without leaving the inline block.

Container Classes

Both modes wrap with not-prose to escape any inherited prose typography styles, plus px-4 sm:px-6 py-3 for default horizontal/vertical padding. Pass extra utilities via class to override.

Source: src/components/reusable/ImageGrid.astro (re-exported from src/components/mdx/index.ts)