Skip to content

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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.

Fern
Snacks
Mushrooms
Tower
Sea star
Honey
Basketball
Breakfast
Tree
Burger
Camera
Coffee
Camping Car
Hats
Tomato basil
Mountain
Bike
<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 />.

1
2
3
4
5
6
7
8
9
10
<Masonry columns={4} spacing={1}>
  {heights.map((height, index) => (
    <MasonryItem key={index}>
      <Item sx={{ height }}>{index + 1}</Item>
    </MasonryItem>
  ))}
</Masonry>

columns accepts responsive values:

1
2
3
4
5
6
7
8
9
10
<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.

1
2
3
4
5
6
7
8
9
10
<Masonry columns={3} spacing={3}>
  {heights.map((height, index) => (
    <MasonryItem key={index}>
      <Item sx={{ height }}>{index + 1}</Item>
    </MasonryItem>
  ))}
</Masonry>

spacing accepts responsive values:

1
2
3
4
5
6
7
8
9
10
<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 />.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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.

1
2
3
4
5
6
7
8
9
10
<Masonry columns={4} spacing={1}>
  {heights.map((height, index) => (
    <MasonryItem key={index} defaultHeight={height}>
      <Item>{index + 1}</Item>
    </MasonryItem>
  ))}
</Masonry>