WebberUI

Masonry Grid

A responsive masonry layout with animated reflow, cards gliding into place as the column count and the data change.

Items are absolutely positioned into whichever column is shortest, producing a staggered masonry flow. The column count changes with the container width, and every card glides into its new place when data is added, removed, or reordered.

Loading preview…
npx shadcn@latest add https://webberui.com/r/masonry-grid.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

3
16
0.05
<MasonryGrid />

Installation

npx shadcn@latest add https://webberui.com/r/masonry-grid.json

Or, once registries are configured in components.json, install it as @webberui/masonry-grid.

Usage

import { MasonryGrid, type MasonryItem } from "@/components/ui/masonry-grid";

const items: MasonryItem[] = [
  { id: "a", height: 200, className: "bg-sky-500" },
  { id: "b", height: 140, className: "bg-rose-500" },
  { id: "c", height: 260, className: "bg-emerald-500" },
];

<MasonryGrid items={items} columns={{ 0: 1, 640: 2, 1024: 3 }} gap={16} />;

columns can be a fixed number (for example 3) or a "container-width breakpoint map": the key is the minimum container width (px) and the value is the column count at or above that width. Breakpoints are decided by the container width rather than the viewport width, so the layout is still correct inside a sidebar or a popover.

Each item's height sets the card height while the width is derived from the column width; put your content in content, or apply a gradient background directly through className.

Props

PropTypeDefaultDescription
itemsMasonryItem[]Grid item data
columnsnumber | Record<number, number>{ 0: 1, 480: 2, 768: 3, 1024: 4 }Fixed column count or a responsive breakpoint map
gapnumber16Gap between cards (px)
durationnumber0.5Duration of a single card's animation (seconds)
staggernumber0.05Interval between cards on reveal (seconds)
animateFrom"bottom" | "top" | "left" | "right" | "center""bottom"Direction the reveal starts from
blurToFocusbooleantrueWhether the reveal goes from blurred to sharp
scaleOnHoverbooleantrueWhether a card scales up slightly on hover
ease[number, number, number, number][0.22, 1, 0.36, 1]Easing curve of the animation

MasonryItem

FieldTypeDescription
idstringUnique identifier; the reflow animation tracks the same card by it
heightnumberCard height (px); the width is derived from the column width
contentReact.ReactNodeCard content; a placeholder panel renders when it is not supplied
classNamestringStyles appended to the card's frame

Accessibility

  • When the user has "reduce motion" enabled at the system level, cards land in place directly with no reveal or reflow animation
  • The layout only renders after the container width has been measured on the client, avoiding a mismatch between server and client (hydration mismatch)
  • A ResizeObserver watches the container width and disconnects automatically on unmount, so any size change reflows immediately

On this page