Material-ui: Add a Masonry Component

Created on 14 Aug 2019  路  12Comments  路  Source: mui-org/material-ui


This references issue #7602. I propose MUI adds a a new Masonry component.

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Summary 馃挕


A masonry component is a grid layout in which "Elements from a single-column format may reflow to fill the content area in various combinations."

The current Grid component with its underlying flexbox does not support this. However, I believe the MUI Grid behavior has its place, and a MUI Masonry can be sufficiently separate and distinct from MUI Grid.

The main interest in having such a component would be to support an aspect of the Material UI specification with a MUI component. As a MUI component, there is more control over the component, making it behave as expected of a MUI component. This gives way to a consolidated definition of component themes, in this case, access to MUI's breakpoint definitions; a MUI-like width range consisting of 1-12, 'auto', and boolean values for MUI's implementation of responsiveness; and custom props such as xs, md, lg, component, spacing, etc. which --again-- give it a more MUI-like behavior expected of MUI components.

This component needs more upvotes to be considered for MUI. This proposal mainly isolates those upvotes for an accurate record of users who would like the MUI library to support this component.

Benchmark

enhancement

Most helpful comment

We weren't expecting this component to be that much requested, but yeah, we will think about something for it :).

All 12 comments

Just a remark, in case this does get enough momentum. I don't want to make excuses, but with this being my senior year, landing a place in programming team, and working, I am utterly swamped. I want to contribute though in anyway I can. If everyone is fine with waiting on me, that's cool and I apologize in advance. However, if someone picks it up, that's cool too I just want to be involved in some way if possible.

Wish there was a masonry component similar to Muuri.js. The gridlist just doesn't cut it.

Any news about this component? I think there is a lot of people which are waiting for something like this :)

We weren't expecting this component to be that much requested, but yeah, we will think about something for it :).

Voting this request up. Have tried a few npm packages and not super confident in performance of any of the ones available. I haven't gotten exactly the expected behavior out of those available. I would be super confident in you guys to put out a reliable component :)

I'm using https://github.com/paulcollett/react-masonry-css for now and it's serving it's purpose well

I'm using https://github.com/paulcollett/react-masonry-css for now and it's serving it's purpose well

Dashue, Thank you for the reference. Right now my cards are in a Grid, but the content will never be even even if I limit the number of items within the card. This is where I get caught up -- for mobile it is not an issue because the grid collapses to one row. I want something that very light that which I can implement only for desktop.

It seems a natural extension of the Grid Component...to just add a prop in there that says collapse vertical whitespace within rows. I get that it is not that simple...

image

I also use react-masonry-css and made a simple wrapper component that takes the breakpoints from the theme and configures the masonry accordingly - works pretty well:

import React from "react";
import PropTypes from "prop-types";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Masonry from "react-masonry-css";

/////////////////////////////////////////
//  Styles
/////////////////////////////////////////

const useStyles = makeStyles((theme) => ({
  root: {
    margin: theme.spacing(3, 0, 2, 0),
  },
  paper: {
    marginBottom: theme.spacing(4),
  },
  masonryGrid: {
    display: "flex",
    marginLeft: theme.spacing(-4),
    width: "inherit",
  },
  masonryColumn: {
    paddingLeft: theme.spacing(4),
    backgroundClip: "padding-box",
  },
}));

/////////////////////////////////////////
//  PropTypes
/////////////////////////////////////////

const propTypes = {
  children: PropTypes.node,
};

/////////////////////////////////////////
//  Component
/////////////////////////////////////////

const BreakpointMasonry = ({ children }) => {
  const classes = useStyles();
  const theme = useTheme();

  const breakpointCols = {
    default: 4,
    [theme.breakpoints.values.xl]: 4,
    [theme.breakpoints.values.lg]: 3,
    [theme.breakpoints.values.md]: 2,
    [theme.breakpoints.values.sm]: 1,
    [theme.breakpoints.values.xs]: 1,
  };

  return (
    <Masonry
      breakpointCols={breakpointCols}
      className={classes.masonryGrid}
      columnClassName={classes.masonryColumn}
    >
      {children}
    </Masonry>
  );
};

BreakpointMasonry.propTypes = propTypes;

export default BreakpointMasonry;

Any updates on this visually it would be so amazing!

Any updates on this visually it would be so amazing!

Did you try the wrapper component I posted above? Just import it and wrap the components you want to show in a masonry with it.

<BreakpointMasonry>
   <...yourComponent>
   <...yourComponent>
   <...yourComponent>
</BreakpointMasonry>

if you need different breakpoints adjust the breakpointCols values to your needs. The numbers just indicate how many columns you want to show at each breakpoint.

can confirm that the wrapper component above works incredibly well!

The above example integrating react-material-css and the MUI theme breakpoints works well.

I also encountered this issue a while ago, and came up with a solution using only MUI by nesting two Grid containers, and dynamically arranging the Grid items into new columns when the width changes (detecting width changes using useWidth()).


I've uploaded a working minimal demo to CodeSandbox in case it helps anyone coming across this thread.

I'm using this prop to dynamically arrange the grid items into columns of customizable widths:

screenWidthToColumns: {
    xs: [12],
    sm: [6, 6],
    md: [4, 6, 2],
    lg: [3, 3, 3, 3],
    xl: [3, 3, 3, 3]
  }

E.g.:
In 'xs' viewport width, there is one column spanning the entire Masonry grid.
In 'sm' viewport width, there are two columns each spanning half the Masonry grid.
In 'md' viewport width, there are three columns spanning the Masonry grid (with different widths).


One of the challenges I've faced with this solution (and also with react-material-css) is that some of the children of the Masonry grid need to be unmounted and remounted into new parents (new columns) when the viewport width changes.

I'm not confident that this is a problem that can be solved when using Masonry layouts with dynamic columns in React though (and it isn't a big problem if you can lift state out of the Masonry grid's children).

Hope this helps someone!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tdkn picture tdkn  路  57Comments

illogikal picture illogikal  路  75Comments

damianobarbati picture damianobarbati  路  55Comments

darkowic picture darkowic  路  62Comments

NonameSLdev picture NonameSLdev  路  56Comments