masonix
Examples

Photo Gallery

A polished image-gallery pattern using known aspect ratios.

Image galleries feel best when the layout can reserve space before media loads. Use known width and height values to compute each rendered item height.

Marfa, TX

Desert dawn

Seattle, WA

Glass house

Reykjavik, IS

Blue hour

Lisbon, PT

Courtyard

Brooklyn, NY

Studio wall

Kyoto, JP

Quiet arch

Busan, KR

Sea path

Portland, OR

Green room

Example

import { clsx } from 'clsx';
import { MasonryBalanced } from 'masonix';

type Photo = {
  id: string;
  title: string;
  location: string;
  gradient: string;
  width: number;
  height: number;
};

function PhotoCard({ photo, width }: { photo: Photo; width: number }) {
  const renderedHeight = Math.round(width * (photo.height / photo.width));

  return (
    <article
      className={clsx(
        'relative overflow-hidden',
        'rounded-xl border',
        'border-white/20',
      )}
      style={{ height: renderedHeight, background: photo.gradient }}
    >
      <div className="absolute inset-0 bg-gradient-to-b from-black/5 via-transparent to-black/60" />
      <div className="absolute inset-x-0 bottom-0 p-4">
        <p className="text-xs font-medium uppercase tracking-wide text-white/65">
          {photo.location}
        </p>
        <h3 className="mt-1 text-base font-semibold text-white">
          {photo.title}
        </h3>
      </div>
    </article>
  );
}

export function PhotoGallery({ photos }: { photos: Photo[] }) {
  return (
    <MasonryBalanced
      items={photos}
      columns={{ 0: 1, 560: 2, 860: 3 }}
      gap={14}
      defaultWidth={960}
      itemKey={(photo) => photo.id}
      getItemHeight={(photo, _itemIndex, columnWidth) =>
        Math.round(columnWidth * (photo.height / photo.width))
      }
      render={({ data, width }) => <PhotoCard photo={data} width={width} />}
    />
  );
}

When to use

Use this when the API already gives image dimensions. It works well for portfolio pages, editorial galleries, and commerce lookbooks.

Notes

  • Known heights reduce layout shift.
  • defaultWidth improves the first server-rendered layout.
  • Keep alt text on the actual image, not on the wrapper.

On this page