EF
EF Design System

Masonry Grid

A CSS column-count based masonry layout for variable-height content. Responsive breakpoints adjust column count for different screen sizes.

Live Demo (3 Columns)

Short card
Tall card
Medium card
Compact card
Feature card
Info card
Detail card
Stat card
Hero card

Basic Implementation

css
.masonry {
  column-count: 3;
  column-gap: 16px;
}

.masonry-item {
  break-inside: avoid;
  margin-bottom: 16px;
  border-radius: 12px;
}

Responsive Breakpoints

Use media queries to reduce column count on smaller screens.

2 Columns (Tablet)

Short card
Tall card
Medium card
Compact card
Feature card
Info card

1 Column (Mobile)

Short card
Tall card
Medium card
css
.masonry {
  column-count: 3;
  column-gap: 16px;
}

/* Tablet: 768px - 1024px */
@media (max-width: 1024px) {
  .masonry {
    column-count: 2;
  }
}

/* Mobile: below 768px */
@media (max-width: 768px) {
  .masonry {
    column-count: 1;
  }
}

Breakpoint Reference

PropTypeDefaultDescriptionRequired
desktop>= 1024px3Three-column layout for wide screensNo
tablet768px - 1023px2Two-column layout for medium screensNo
mobile< 768px1Single-column stack for small screensNo
column-gappx16pxHorizontal space between columnsNo
item-gappx (margin-bottom)16pxVertical space between itemsNo

React Component

tsx
function MasonryGrid({
  children,
  columns = 3,
  gap = 16,
}: {
  children: React.ReactNode;
  columns?: number;
  gap?: number;
}) {
  return (
    <div style={{ columnCount: columns, columnGap: gap }}>
      {children}
    </div>
  );
}

function MasonryItem({ children }: { children: React.ReactNode }) {
  return (
    <div style={{ breakInside: "avoid", marginBottom: 16 }}>
      {children}
    </div>
  );
}

Guidelines

  • Always set break-inside: avoid on child items to prevent splitting across columns.
  • CSS columns fill top-to-bottom, then left-to-right. Keep this in mind for reading order.
  • Use consistent item border-radius (min 8px) and spacing.
  • For very long lists, consider virtualizing with a library.