Masonry Grid
A pure-CSS waterfall grid that stacks children into responsive columns without measuring layout.
Loading preview…
Installation
npx shadcn@latest add https://ui.zyeon.ai/r/masonry-grid.jsonPrompt
Build a React + TypeScript + Tailwind "MasonryGrid" layout container. No
external dependencies beyond Tailwind and the shared cn() class-merge helper.
Contract
- Named export `MasonryGrid`, typed with `MasonryGridProps`:
- `columns?: { base?: 1|2|3|4; sm?: 1|2|3|4; lg?: 1|2|3|4 }` — defaults to
`{ base: 1, sm: 2, lg: 3 }`.
- `gap?: number` — px, default `16`.
- `children`, `className`, plus the rest of native `div` props spread onto
the root element.
Behavior
- Wrap each child in its own `break-inside-avoid` div (via `React.Children.map`)
so CSS multi-column layout never splits one item across a column break.
- Layout is pure CSS — no measuring, no ResizeObserver, no reflow logic in
JS. This stays a Server Component: no "use client", no hooks, no events.
- Item order follows column-fill order (top-to-bottom down one column, then
the next), not row-major reading order — flag this to callers who need
strict left-to-right sequence, they should reach for something else.
- `gap` drives a single CSS custom property (`--masonry-gap`) applied to both
the container's `column-gap` and every wrapper's `margin-bottom`, so
horizontal and vertical spacing stay in sync from one number.
Rendering & styling
- Column count per breakpoint resolves through three fixed lookup objects
(base/sm/lg) mapping 1|2|3|4 to literal Tailwind classes ("columns-2",
"sm:columns-3", …) — never build class names by string interpolation
(`columns-${n}`), or Tailwind's build-time class scanner won't find them.
- `cn()` merges the resolved column classes with the consumer's `className`.
- No visual chrome of its own beyond the layout primitives — it only
arranges whatever children are passed in, so it carries no color tokens.
Customization levers
- Column counts per breakpoint (`columns.base/sm/lg`, 1–4) — tune density.
- `gap` — spacing between both columns and stacked items.
- Extend to more breakpoint tiers (e.g. `md`, `xl`) by adding entries to the
same three lookup tables, if a project needs finer-grained control.
- Pair with an image lightbox (wrap each `<img>` child in a click handler) or
a stagger-in entrance animation on the children — MasonryGrid itself stays
layout-only and doesn't own those behaviors.Concepts
- Column-fill order — CSS
columnslays items down the first column before wrapping to the next, so masonry order is column-major, not left-to-right reading order. - break-inside-avoid wrapper — every child is wrapped in its own div carrying
break-inside-avoidso an item is never split across a column break. - Static column class map —
columns-1..4per breakpoint come from a fixed lookup object, not a template string likecolumns-${n}, so Tailwind's build-time scanner can see every class that might render. - CSS var gap — one
--masonry-gapcustom property drives bothcolumn-gap(between columns) and each wrapper'smargin-bottom(between stacked items), keeping spacing in sync from a singlegapprop. - No measuring, no JS — pure CSS layout, no
ResizeObserver, no height measurement, no"use client"— that's what keeps this a zero-JS Server Component and why it's a poor fit for strict visual ordering (reach for a JS masonry library instead).
Carousel
An embla-powered slide carousel — autoplay with hover-pause, looped or bounded navigation, arrow buttons and synced pagination dots.
Video Embed
A lite facade for YouTube/Vimeo — a poster and play button stand in for the real iframe until the user clicks, so no third-party embed script ever loads uninvited.