Block Gallery — React Page Block
Work gallery: a responsive grid of tiles that lift on hover, with an optional lightbox — a real dialog (focus moves in, Escape closes, arrows navigate, Tab stays trapped, focus returns).

Usage
import { BlockGallery } from "@/components/BlockGallery";
export function Work() {
return (
<BlockGallery
title="Recent releases, up close."
items={[
{ title: "Fieldnote launch", caption: "2026 · identity + site", media: <img src="/work/fieldnote.png" alt="" /> },
{ title: "Orbit 2.4", caption: "2026 · product film" },
]}
{...{
title: "Recent releases, up close.",
lightbox: true,
accent: "#d5ed9a",
scheme: "dark"
}}
/>
);
}Implementation notes & API
Purpose: portfolio/work gallery with an accessible lightbox. Copy it, ship it — every string, link and color arrives through props. Runtime: pure DOM + CSS. No WebGPU, canvas, animation library or external assets; SSR-safe on first render. Theming: root custom properties (--vb-bg, --vb-fg, --vb-accent, --vb-border, --vb-radius, --vb-container) or the accent/scheme/className/style props. scheme flips the dark default to light. Guardrails: responsive via container queries down to 320px; interactive behavior degrades on touch; prefers-reduced-motion drops entrance/scroll motion while content stays complete. The default artwork is fictional CSS scenery visibly marked as demo; pass media for real screenshots and photography.
| Property | Type | Notes / default |
|---|---|---|
eyebrow / title / description | ReactNode | Section header |
items | readonly GalleryItem[] | { title, caption?, media? } — media is any node; default artwork is generated in CSS |
lightbox | boolean | true; tiles open the dialog when set |
closeLabel / previousLabel / nextLabel | string | Accessible labels for the dialog controls |
demoNote | ReactNode | null | Fictional-artwork marker; pass null with real work |
scheme | "dark" | "light" | dark |
accent | string (hex) | Sets --vb-accent for the whole block |
className / style | string / CSSProperties | Applied to the section root |
children | ReactNode | Replaces the default content entirely |