5
votes

1. Current Appearance

I have a Material UI Grid container with 4 Grid items. Within each Grid item is a Typography component containing a title and a Card with some content, as shown below:

enter image description here

2. Desired appearance

I would like the Cards to fill the remaining height of the Grid items and not exceed it. This is my desired output:

enter image description here

3. Undesirable appearance (card height = 100%)

I have tried making the height of the Cards 100% but this means each Card takes on the height of its parent (the Grid item), and the height of the parent = Typography + Card (rather than the remaining space minus the Typography), so the result is that the Card then exceeds the height of the parent Grid item as below:

enter image description here

What is the best way to overcome this problem? I'm using Material UI's Grid to make the breakpoints easy and consistent with the rest of my project, so ideally the solution would use that approach.

Here is the code:

import React from 'react';

const useStyles = makeStyles(theme => ({
   // stretch: { height: '100%' }, // Un-commenting this results in undesirable appearance 3 (see image 3 above)
    outline: { border: '1px solid red' },
}));

const Sections= () => {
  const classes = useStyles();

  return (
    <Grid container spacing={3} justify="space-between" alignItems="stretch" className={classes.outline}>
      <Grid item xl={2} lg={2} md={6} xs={12} className={classes.outline}>
          <Typography className={classes.outline}>Big title 1</Typography>
          <Card className={classes.stretch}><CardContent>Lots and lots and lots and lots and lots and lots of content</CardContent></Card>
      </Grid>
   <Grid item xl={4} lg={4} md={6} xs={12} className={classes.outline}>
          <Typography className={classes.outline}>Big title 2</Typography>
          <Card className={classes.stretch}><CardContent>Not much content</CardContent></Card>
   </Grid>
   <Grid item xl={3} lg={3} md={6} xs={12} className={classes.outline}>
          <Typography className={classes.outline}>Big title 3</Typography>
          <Card className={classes.stretch}><CardContent>Not much content</CardContent></Card>
   </Grid>
   <Grid item xl={3} lg={3} md={6} xs={12} className={classes.outline}>
          <Typography className={classes.outline}>Big title 4</Typography>
          <Card className={classes.stretch}><CardContent>Not much content</CardContent></Card>
   </Grid>
</Grid>
  );
};


export default Sections;

Many thanks,

Katie

2
I think you are missing some parts of the code. Such as the additional "Big Title"s above each of the cards. Would you be able to update the code snippet to include it? Thanks - Charles Kornoelje
I have created a stackblitz live example which I believe has your desired outcome. Interestingly, I uncommented the styles you had and it seems to be working. There were some issues where your <Grid /> tags weren't in the right order so maybe that's why your styling didn't work before. - Charles Kornoelje
Thanks Charles - I have amended the code and hope it now looks correct? I also realise, as you suggest, that there is a closing </Grid> tag in the wrong place. Other than that, I can see that your code is working, but I don't understand the difference? I have had to massively simplify the code shown here vs my own code, so I'm trying to unpick the difference! Do you mind explaining? Many thanks! - Katie7
Actually - I can see that I'm afraid that solution doesn't work. If you apply a border to the grids then you can see that it resembles the image 3 above. The Cards extend beyond the height of the parent Grid. Many thanks for your help! - Katie7
Katie, I realized the issue in my first solution and have updated it. I hope it helps! Thanks for the pictures showing what outcomes were desired. - Charles Kornoelje

2 Answers

2
votes

To solve this, you need to set a height for each individual Grid Item. Then you can display the Grid Item flexed with the flex-direction of "column". Next, you can set the height of the card to 100% as you had before. The default display mechanism in the Material-UI grid is not set to flex so the card will extend outside of the border since they use things like negative margins.

The code is below:

// imports omitted

const useStyles = makeStyles(theme => ({
  stretch: { height: "100%" },
  item: { display: "flex", flexDirection: "column" } // KEY CHANGES
}));

export const Sections = () => {
  return (
    <Grid container spacing={2} justify="space-between" alignItems="stretch">
      <Item xl={2} lg={2} md={6} xs={12} title="Big Title 1" content="Lots and lots and lots and lots and lots and lots of content!" />
      <Item xl={4} lg={4} md={6} xs={12} title="Big Title 2" content="Not much content" />
      <Item xl={3} lg={3} md={6} xs={12} title="Big Title 3" content="Not much content" />
      <Item xl={3} lg={3} md={6} xs={12} title="Big Title 4" content="Not much content" />
    </Grid>
  );
}

const Item = ({ title, content, ...rest }) => {
  const classes = useStyles();

  return (
    <Grid className={classes.item} item {...rest}>
      <Typography>{title}</Typography>
      <Card className={classes.stretch}>
        <CardContent>{content}</CardContent>
      </Card>
    </Grid>
  );
};

Checkout stackblitz for a live example.

1
votes

to make the Card remaining height always, give a height to Typography. let's say the height of Typography is 20px and then set the height of the CardItem as 100% - (height of the typography_ i.e; `height:'calc(100% - 20px)'. It'll take the remaining height.

const useStyles = makeStyles((theme) => ({
    stretch: {
        height: 'calc(100% - 20px)'
    }, // Un-commenting this results in undesirable appearance 3 (see image 3 above)
    outline: { border: "1px solid red" }
}));
<Grid
  container
  spacing={3}
  justify="space-between"
  alignItems="stretch"
  className={classes.outline}>
  <Grid item xl={2} lg={2} md={6} xs={12} className={classes.outline}>
    <Typography style={{height:'20px'}} className={classes.outline}>Big title 1</Typography>
    <Card className={classes.stretch}>
      <CardContent>
        Lots and lots and lots and lots and lots and lots of content
      </CardContent>
    </Card>
  </Grid>
  <Grid item xl={4} lg={4} md={6} xs={12} className={classes.outline}>
    <Typography style={{height:'20px'}} className={classes.outline}>Big title 2</Typography>
    <Card className={classes.stretch}>
      <CardContent>Not much content</CardContent>
    </Card>
  </Grid>
  <Grid item xl={3} lg={3} md={6} xs={12} className={classes.outline}>
    <Typography style={{height:'20px'}} className={classes.outline}>Big title 3</Typography>
    <Card className={classes.stretch}>
      <CardContent>Not much content</CardContent>
    </Card>
  </Grid>
  <Grid item xl={3} lg={3} md={6} xs={12} className={classes.outline}>
    <Typography style={{height:'20px'}} className={classes.outline}>Big title 4</Typography>
    <Card className={classes.stretch}>
      <CardContent>Not much content</CardContent>
    </Card>
  </Grid>
</Grid>

Edit gallant-violet-k9tqs