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.
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.
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
npx shadcn add "https://ui.beste.co/r/gallery28?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
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.
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.
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:
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" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small-caps line above the heading |
heading | string | – | Section heading, rendered as an h2 through Text1 |
button | ActionButton | – | Pill action beside the heading |
plates | Plate[] | [] | The photographs, each with its own crop |
labels | Gallery28Labels | {} | Control names and the counter wording |
className | string | – | Extra classes for the outer <section> |
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";
};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.figure with a real figcaption, so the subject and place stay attached to the picture rather than being two spans that follow it.cursor-w-resize or cursor-e-resize cursor, so the whole picture is a page-turn target and the cursor says which way.role="dialog" with aria-modal, Escape to close, arrow keys to step, and document.body.style.overflow locked while open and restored on unmount.stopPropagation, so using the controls never dismisses the whole thing by accident.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.gallery29
An even three-column grid of photographic plates that open into an ink lightbox: every frame keeps the same ratio so the captions line up, arrows and keys turn the page, either half of the plate is clickable, and a plate that belongs to a page offers it as a link.
gallery1
Masonry gallery built with CSS columns so images keep their own heights, each captioned with its subject and place, and any frame opening a drawer that slides in from the right while the wall stays visible behind the scrim.
gallery2
Captioned image grid where any tile opens a full-screen lightbox on a dark scrim, with a frame counter, keyboard arrows, escape to close and previous and next controls beside the caption.
gallery26
A square cover grid that names each picture only on hover and opens it full screen on click, where arrows and the keyboard walk the archive and a link leads into the issue itself.