Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Masonry Component #17000

Closed
1 task done
weiluntong opened this issue Aug 14, 2019 · 28 comments · Fixed by #27439
Closed
1 task done

Add a Masonry Component #17000

weiluntong opened this issue Aug 14, 2019 · 28 comments · Fixed by #27439
Labels
component: masonry This is the name of the generic UI component, not the React module! new feature New feature or request

Comments

@weiluntong
Copy link

weiluntong commented Aug 14, 2019

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

  • 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.

Capture d’écran 2020-12-28 à 00 49 39

Benchmarks

@oliviertassinari oliviertassinari added new feature New feature or request waiting for 👍 Waiting for upvotes labels Aug 15, 2019
@weiluntong
Copy link
Author

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.

@oliviertassinari oliviertassinari removed the waiting for 👍 Waiting for upvotes label Nov 30, 2019
@oliviertassinari oliviertassinari added priority: important This change can make a difference and removed priority: important This change can make a difference labels Nov 30, 2019
@bluefire2121
Copy link

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

@WojtekHerisz
Copy link

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

@oliviertassinari
Copy link
Member

oliviertassinari commented Mar 4, 2020

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

@megphillips91
Copy link

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 :)

@Dashue
Copy link

Dashue commented May 4, 2020

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

@megphillips91
Copy link

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

@chrishoermann
Copy link

chrishoermann commented Jun 5, 2020

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;

@crimson-med
Copy link

Any updates on this visually it would be so amazing!

@chrishoermann
Copy link

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.

@majelbstoat
Copy link

can confirm that the wrapper component above works incredibly well!

@mui mui deleted a comment from modbender Jul 10, 2020
AlbertoPdRF added a commit to AlbertoPdRF/albertopdrf.com that referenced this issue Aug 3, 2020
@HarmanSran
Copy link

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!

@GuillaumeDesforges
Copy link

@chrishoermann awesome wrapper! Thanks for sharing this.

Although, an actual component shipped by MUI would be perfect.

@atnpcg
Copy link

atnpcg commented Dec 7, 2020

This is something I'm interested to start working on, if no one has started working on it yet

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 7, 2020

@atnpcg I'm not aware anyone is working on it, you are clear to go :). I think that the first step is to get a pretty clear picture of what should be built. What problem did developers face when coming here to upvote the issue?

@atnpcg
Copy link

atnpcg commented Dec 7, 2020

@oliviertassinari for me it was a stop when trying to implement it with cards in a masonry layout like shown on:
https://material.io/components/cards#behavior (last example) although there is no mention about this kind of layout in material.io

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 7, 2020

@atnpcg I have updated the Benchmarks section in the issue description, which link matches the closest to what you need?

@atnpcg
Copy link

atnpcg commented Dec 7, 2020

@oliviertassinari
I think the one provided on https://paulcollett.github.io/react-masonry-css/demo/
is the one more flexible, that allows you to have different number of columns per breakpoint and can render any child
but of course, will be better if we use our current breakpoints plus possibility of using the theme spacing

@atnpcg
Copy link

atnpcg commented Dec 7, 2020

I think also what we have on https://next.material-ui.com/components/image-list/#masonry-image-list is close enough, but currently is just a variation for the ImageList, we can try start by there, extracting some of the logic and have it as a standalone component

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 7, 2020

@atnpcg We can benchmark what the ImageList is doing but it's a great opportunity to challenge the implementation. Happy to try https://paulcollett.github.io/react-masonry-css/demo/ out, it seems to have a nice compromise in terms of simplicity. Regarding the breakpoint API, I would suggest we use the same one as the system: https://next.material-ui.com/system/basics/#responsive-values. It will also be an opportunity to implement a useBreakpointValue() helper.

@mbrookes
Copy link
Member

mbrookes commented Dec 7, 2020

@atnpcg Despite the new name, an ImageListLtem's child doesn't have to be an image. (Even the MD spec alludes to this IIRC). It would be trivial to set the cols prop based on useWidth for responsiveness. The main issue is that the grid content is laid out in columns, rather than filling horizontally.

The challenge would be reordering the items so that they are distributed from left-to-right, rather than top-to-bottom. That's probably going to be a performance suck. Also, beware accessibility concerns, and how infinite scroll could work with that approach.

There's experimental native masonry grid layout in Firefox, but that's too early for our use.

@GuillaumeDesforges
Copy link

there is no mention about this kind of layout in material.io

https://material.io/components/image-lists#usage, section "Types", item 4 is Masonry image lists (yes, it's deep)

@atnpcg
Copy link

atnpcg commented Dec 7, 2020

The main issue is that the grid content is laid out in columns, rather than filling horizontally.

you are right @mbrookes and even the library we are suggesting, is rendered in columns, affecting accessibility (screen readers will read top to bottom instead of left to right), also focusable elements will have a top to bottom flow, unless we start detecting what elements are focusable and calculate every single focusIndex.

@atnpcg
Copy link

atnpcg commented Dec 8, 2020

My first approach was to use Grid component inside of Masonry,
although it work, it adds the limitation of having only 1, 2, 3, 4 or 6 columns , I will remove the Grid dependency, and just use CSS for the spacing

#23954

image

antoniopacheco added a commit to antoniopacheco/material-ui that referenced this issue Dec 11, 2020
Masonry component will render children from left to right, accepting cols and spacing props

fix mui#17000
antoniopacheco added a commit to antoniopacheco/material-ui that referenced this issue Dec 11, 2020
Masonry component will render children from left to right, accepting cols and spacing props

fix mui#17000
This was referenced Dec 11, 2020
@oliviertassinari
Copy link
Member

Considering the high volume of upvotes for this issue, and the large spectrum of the different solutions that we can build, we have created a survey to identify the most frequent pain points. There are 5 questions, it shouldn't take more than 1 minute to fill:

Take the survey! 📣 🙏

@oliviertassinari
Copy link
Member

oliviertassinari commented Mar 29, 2021

It seems that we have a use case for a Masonry component in the marketing pages of Material-UI:

Screenshot 2021-03-29 at 19 50 24

@BM-BrunoMarques

This comment has been minimized.

@hbjORbj
Copy link
Member

hbjORbj commented Oct 1, 2021

@weiluntong @bluefire2121 @atnpcg @GuillaumeDesforges @chrishoermann @WojtekHerisz @Dashue @HarmanSran @megphillips91

For your information, Masonry component is now live as part of@mui/lab. Its details can be found here.

It comes with a limitation which is explained in this issue.

To address this limitation, a new implementation for Masonry is waiting in this PR.

In short,

  • the current masonry fails to render items beyond 2,000px but it supports column spanning.
  • the new masonry renders all items as expected but it doesn't support column spanning.

I would really appreciate if you could share your preference between the two! You can leave your comments in either the PR for new masonry or in the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: masonry This is the name of the generic UI component, not the React module! new feature New feature or request
Projects
None yet