Skip to main content
Version: Next

MasonryGrid

MasonryGrid is the right layout primitive when items should keep their natural height and pack into columns without leaving the dead space you get from strict row alignment.

Best For

  • Uneven-height cards
  • Gallery-style layouts
  • Dashboard and content walls
  • Visually packed columns

Import

import { MasonryGrid } from '@editora/ui-react';
// or subpath
import { MasonryGrid } from '@editora/ui-react/MasonryGrid';

Basic Usage

<MasonryGrid columns={{ initial: 1, md: 2, lg: 3 }} gap="lg">
<article>Short card</article>
<article>Taller card with more content</article>
<article>Medium card</article>
</MasonryGrid>

Uneven-Height Cards

import { Card, MasonryGrid } from '@editora/ui-react';

function UnevenCardsExample() {
return (
<MasonryGrid columns={{ initial: 1, md: 2, lg: 3 }} gap="lg">
<Card style={{ padding: 20, minHeight: 140 }}>Short summary</Card>
<Card style={{ padding: 20, minHeight: 260 }}>
Longer editorial note with more copy and metadata.
</Card>
<Card style={{ padding: 20, minHeight: 180 }}>Medium card</Card>
<Card style={{ padding: 20, minHeight: 320 }}>
Research digest with multiple sections.
</Card>
</MasonryGrid>
);
}
import { Card, MasonryGrid } from '@editora/ui-react';

const images = [
{ id: 1, h: 180, src: '/img/gallery-1.jpg', alt: 'Editorial cover study' },
{ id: 2, h: 280, src: '/img/gallery-2.jpg', alt: 'Campaign moodboard' },
{ id: 3, h: 220, src: '/img/gallery-3.jpg', alt: 'Product still life' },
{ id: 4, h: 340, src: '/img/gallery-4.jpg', alt: 'Archive photography' }
];

function GalleryExample() {
return (
<MasonryGrid columnWidth="220px" gap="md">
{images.map((image) => (
<Card
key={image.id}
style={{
padding: 12,
borderRadius: 24,
overflow: 'hidden'
}}
>
<img
src={image.src}
alt={image.alt}
style={{
width: '100%',
height: image.h,
objectFit: 'cover',
display: 'block',
borderRadius: 18
}}
/>
</Card>
))}
</MasonryGrid>
);
}

Dashboard And Content Walls

import { Badge, Card, Flex, MasonryGrid } from '@editora/ui-react';

function DashboardWallExample() {
return (
<MasonryGrid columns={{ initial: 1, md: 2, xl: 4 }} gap="lg">
<Card style={{ padding: 14, minHeight: 280, borderRadius: 24, overflow: 'hidden' }}>
<Flex direction="column" gap="10px">
<img
src="/img/dashboard-revenue.jpg"
alt="Revenue dashboard preview"
style={{ width: '100%', height: 132, objectFit: 'cover', display: 'block', borderRadius: 16 }}
/>
<Badge tone="brand">Revenue</Badge>
<div>$128K this month</div>
</Flex>
</Card>

<Card style={{ padding: 14, minHeight: 352, borderRadius: 24, overflow: 'hidden' }}>
<img
src="/img/dashboard-activity.jpg"
alt="Team activity feed preview"
style={{ width: '100%', height: 176, objectFit: 'cover', display: 'block', borderRadius: 16, marginBottom: 12 }}
/>
Team activity feed
</Card>
<Card style={{ padding: 14, minHeight: 300, borderRadius: 24, overflow: 'hidden' }}>
<img
src="/img/dashboard-approvals.jpg"
alt="Approvals queue preview"
style={{ width: '100%', height: 150, objectFit: 'cover', display: 'block', borderRadius: 16, marginBottom: 12 }}
/>
Approvals queue
</Card>
<Card style={{ padding: 14, minHeight: 300, borderRadius: 24, overflow: 'hidden' }}>
<img
src="/img/dashboard-summary.jpg"
alt="Performance narrative preview"
style={{ width: '100%', height: 180, objectFit: 'cover', display: 'block', borderRadius: 16, marginBottom: 12 }}
/>
Performance narrative and trends
</Card>
</MasonryGrid>
);
}

Visually Packed Columns

import { Card, MasonryGrid } from '@editora/ui-react';

function PackedColumnsExample() {
return (
<MasonryGrid columns={4} columnGap="md" itemGap="md" fill="balance">
{Array.from({ length: 12 }).map((_, index) => (
<Card
key={index}
style={{
padding: 16,
minHeight: 120 + (index % 4) * 50
}}
>
Column item {index + 1}
</Card>
))}
</MasonryGrid>
);
}

Props

PropTypeDescription
columnsResponsive<string | number>Number of columns
columnWidthResponsive<string | number>Preferred column width
gapResponsive<string | number>Shared horizontal and vertical spacing
columnGapResponsive<string | number>Space between columns
itemGapResponsive<string | number>Space between stacked items
fillResponsive<'auto' | 'balance' | 'balance-all' | string | number>Column balancing strategy
displayResponsive<string | number>Host display override
headlessbooleanHide the host entirely

Notes

  • MasonryGrid uses CSS multi-column layout, so visual scan order follows columns.
  • Use columnWidth for gallery-style walls and columns for more dashboard-like control.
  • If visual row order must exactly match reading order, use PlacementGrid instead.