Masonry

An animated masonry grid that lays out image items by explicit height, with configurable entry and hover animations.

Masonry takes an array of items (each with an img and a pixel height) and lays them out into a responsive column grid, animating each tile in and reacting to hover.

Preview

Installation

$ npx shadcn@latest add https://spark-ui-olive.vercel.app/r/masonry.json

Usage

import { Masonry } from "@/components/masonry";
const ITEMS = [
  { id: "1", img: "/images/trail-1.jpg", height: 400 },
  { id: "2", img: "/images/trail-2.jpg", height: 250 },
  { id: "3", img: "/images/trail-3.jpg", height: 600 },
  { id: "4", img: "/images/trail-4.jpg", height: 350 },
  { id: "5", img: "/images/trail-5.jpg", height: 300 },
  { id: "6", img: "/images/trail-1.jpg", height: 450 },
  { id: "7", img: "/images/trail-2.jpg", height: 320 },
  { id: "8", img: "/images/trail-3.jpg", height: 400 },
];

export default function MasonryDemo() {
  return (
    <Masonry
      items={ITEMS}
      className="max-w-5xl"
      ease="power3.out"
      duration={0.6}
      stagger={0.05}
      animateFrom="bottom"
      scaleOnHover
      hoverScale={0.95}
      blurToFocus
      colorShiftOnHover={false}
    />
  );
}

Examples

Cards

Pass renderItem to render custom content — like a title and description overlay — instead of the default image tile.

Properties

PropTypeDefaultDescription
items{ id: string; img: string; url?: string; height: number }[]Items to arrange. `height` sets the tile's pixel height; `url` (optional) makes the tile a link.
easeEasing"easeOut"Framer Motion easing for the entry/hover transitions. Common gsap ease names (e.g. "power3.out") are mapped automatically.
durationnumber0.6Entry animation duration in seconds.
staggernumber0.05Delay in seconds added per item, in layout order.
animateFrom"top" | "bottom" | "left" | "right" | "center" | "random""bottom"Direction each tile animates in from on mount.
scaleOnHoverbooleantrueWhether tiles scale on hover.
hoverScalenumber0.95Scale factor applied on hover when scaleOnHover is enabled.
blurToFocusbooleantrueWhether tiles start blurred and sharpen in as they animate on mount.
colorShiftOnHoverbooleanfalseWhether a color overlay fades in over a tile on hover.
renderItem(item: T, index: number) => ReactNodeOverrides the default image tile with custom content, while keeping the same layout, entry and hover animations.
classNamestringAdditional classes for the grid container.

Accessibility

  • Tiles with a url render as links (<a>); tiles without one are non-interactive.
  • Provide meaningful img sources; decorative tiles otherwise render with an empty alt.