Light Masonry

Around the rooms

Whatthelightdoeshere,monthbymonth.

About this block

Light MasonryPRO

A three-column masonry of photographs in mixed aspects, each rising into view and drifting inside its frame as the page scrolls, with a serif subject and a small-caps place and month under every plate; any plate opens a paper-toned lightbox that sets the subject large beside the picture, turns pages by clicking either half of the plate, the arrows or the keyboard, and slides each plate in from the side it came from.

Gallery28: Light Masonry

A light masonry gallery of mixed crops, each plate drifting inside its frame, opening into a paper-coloured lightbox where the subject is set large beside the picture and either half of it turns the page.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/gallery28?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/gallery28?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/gallery28.tsx plus the button22 sliding-marker pill and the text1 word stagger it uses.

Quick start

The installed file exports gallery28Demo alongside the block: the exact props behind the preview above. Spread it to get a working gallery in one line.

tsx
import { Gallery28, gallery28Demo } from "@/components/beste/block/gallery28";

export default function Page() {
  return <Gallery28 {...gallery28Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Gallery28 } from "@/components/beste/block/gallery28";

export default function Page() {
  return (
    <Gallery28
      eyebrow="Around the rooms"
      heading="What the light does here, month by month."
      button={{ label: "See the rooms in person", href: "/visit", tone: "outline" }}
      plates={[
        {
          src: "/rooms/front.jpg",
          alt: "A sunlit room with plaster walls",
          aspect: "portrait",
          subject: "Front room",
          where: "Rua da Prata, January",
        },
      ]}
      labels={{ previous: "Previous plate", next: "Next plate", close: "Close", open: "Open plate", plate: "Plate", of: "of" }}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstring–Small-caps line above the heading
headingstring–Section heading, rendered as an h2 through Text1
buttonActionButton–Pill action beside the heading
platesPlate[][]The photographs, each with its own crop
labelsGallery28Labels{}Control names and the counter wording
classNamestring–Extra classes for the outer <section>
ts
type Plate = {
  src: string;
  alt: string;
  aspect: "portrait" | "landscape" | "square";
  subject: string;
  where: string;
};

type Gallery28Labels = {
  previous?: string;
  next?: string;
  close?: string;
  open?: string;
  plate?: string;
  of?: string;
};

type ActionButton = {
  label: string;
  href: string;
  tone?: "primary" | "light" | "dark" | "outline";
};

Behavior notes

  • The layout is CSS columns with break-inside-avoid on each figure, not a grid, so plates of three different crops pack without leaving gaps and without any height being measured in JavaScript.
  • aspect is a fixed union rather than a free string, and it maps to one of three Tailwind classes; that is what lets the mixed crops stay on the design's ratios rather than following whatever the source file happens to be.
  • Each plate is a figure with a real figcaption, so the subject and place stay attached to the picture rather than being two spans that follow it.
  • The lightbox tracks direction as well as index, so stepping forward slides the next plate in from the right and stepping back reverses it; that is what makes it read as turning pages.
  • Either half of the open plate is a full-height button with a cursor-w-resize or cursor-e-resize cursor, so the whole picture is a page-turn target and the cursor says which way.
  • It is a real dialog: role="dialog" with aria-modal, Escape to close, arrow keys to step, and document.body.style.overflow locked while open and restored on unmount.
  • Clicking the backdrop closes it while the inner grid calls stopPropagation, so using the controls never dismisses the whole thing by accident.
  • Unlike its dark filmstrip sibling, the backdrop here is bg-background/95 with a backdrop blur, so the page behind stays faintly visible and the plate reads as a page rather than a projection.

More Gallery blocks

View all Gallery
PRO

gallery29

Plate Grid Lightbox

PRO

gallery1

Masonry Caption Gallery

PRO

gallery2

Lightbox Frame Grid

Get Pro access