Masonry
Masonry lays out contents of different sizes as blocks of the same width and variable height with configurable gaps.
Masonry maintains a list of content blocks with a consistent width but variable height. The contents are ordered by row. If a row is already filled with the specified number of columns, the next item starts another row, and it is added to the shortest column.
Warning: This component has been developed with the use of CSS Grid Level 2. Unfortunately, Chrome only allows to render at most 1,000 rows for each grid. Hence, with the current design, a masonry component has a maximum height of 2,000px, and the items beyond this height will fail to be rendered. An issue has been created on GitHub to gather workarounds for this limitation. It is worth noting that this limitation does not exist on Firefox or Safari.
Basic masonry
A simple example of a <Masonry />
. <Masonry />
is a container for one or more <MasonryItem />
s. <MasonryItem />
can receive any element including <div />
and <img />
. Also, it is important to note that each <MasonryItem />
accepts only one element.
<Masonry columns={4} spacing={1}>
{heights.map((height, index) => (
<MasonryItem key={index}>
<Item sx={{ height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
Image masonry
This example demonstrates the use of <Masonry />
for images. <Masonry />
orders its children by row.
If you would like to order images by column, you can use <ImageList variant="masonry" />
. More details on this component can be found in Masonry Image List.
<Masonry columns={3} spacing={1}>
{itemData.map((item) => (
<MasonryItem key={item.img}>
<img
src={`${item.img}?w=162&auto=format`}
srcSet={`${item.img}?w=162&auto=format&dpr=2 2x`}
alt={item.title}
loading="lazy"
/>
</MasonryItem>
))}
</Masonry>
Columns
This example demonstrates the use of the columns
to configure the number of columns of a <Masonry />
.
<Masonry columns={4} spacing={1}>
{heights.map((height, index) => (
<MasonryItem key={index}>
<Item sx={{ height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
columns
accepts responsive values:
<Masonry columns={{ xs: 3, sm: 4 }} spacing={1}>
{heights.map((height, index) => (
<MasonryItem key={index}>
<Item sx={{ height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
Spacing
This example demonstrates the use of the spacing
to configure the spacing between <MasonryItem />
s.
It is important to note that spacing
is a factor of the theme's spacing.
<Masonry columns={3} spacing={3}>
{heights.map((height, index) => (
<MasonryItem key={index}>
<Item sx={{ height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
spacing
accepts responsive values:
<Masonry columns={3} spacing={{ xs: 1, sm: 2, md: 3 }}>
{heights.map((height, index) => (
<MasonryItem key={index}>
<Item sx={{ height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
Column spanning
This example demonstrates the use of the columnSpan
to configure the number of columns taken up by each <MasonryItem />
.
<Masonry columns={4} spacing={1}>
{itemData.map((item, index) => (
<MasonryItem key={index} columnSpan={item.span}>
<Item sx={{ height: item.height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
However, you have to choose the value of columnSpan
for each item carefully or fine-tune heights of items so that your masonry does not break.
<Masonry columns={4} spacing={1}>
{itemData.map((item, index) => (
<MasonryItem key={index} columnSpan={item.span}>
<Item sx={{ height: item.height }}>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>
Server-side rendering
This example demonstrates the use of the defaultHeight
to configure a fixed height of each <MasonryItem />
. This is used for server-side rendering.
By default, height: 100%
will be set to the content of <MasonryItem />
. If you change this, there can be unwanted gap between <MasonryItem />
and the content that you pass to it.
<Masonry columns={4} spacing={1}>
{heights.map((height, index) => (
<MasonryItem key={index} defaultHeight={height}>
<Item>{index + 1}</Item>
</MasonryItem>
))}
</Masonry>