'MUI - V5 Grid System spacing not producing gutters between Grid Items
I am just learning Material UI with react. Starting with V5. I have a basic 12 column grid just to learn this. The spacing is just not working properly. It is just creating a weird padding on the grid items where the items themselves are getting internal padding and I don't see the gutters.
I tested it on the most basic example to ensure its as simple to see:
Here is the code:
//MuiGrid.js
import React from 'react'
import {Grid, Typography, Box} from '@mui/material';
export default function MuiGrid() {
return (
<Box>
<Typography variant='h2'>MUI Grid!</Typography>
{/* Testing Grid Spacing */}
<Box component='section'>
<Typography variant='h5'>Testing Spacing</Typography>
<Box>
<Grid container spacing={2}>
<Grid item sx={{backgroundColor: 'primary.dark'}}>Item 1</Grid>
<Grid item sx={{backgroundColor: 'primary.main'}}>Item 2</Grid>
<Grid item sx={{backgroundColor: 'primary.light'}}>Item 3</Grid>
</Grid>
</Box>
</Box>
</Box>
)
}
I have managed to reproduce this with my first sandbox. Here is the link: https://codesandbox.io/s/quirky-lake-50pqf5?file=/src/Demo.tsx
Here are the screenshots before & after spacing is applied, it shows just odd padding:
All the documentation is very vague and only shows basic information & I can't see what I have done wrong here
Edit 2:
I tried to make spacing 0 and add padding as suggested by the answer, that works well to provide padding but I can't get gutters
See code:
<Box component='section'>
<Typography variant='h5'>Testing Spacing</Typography>
<Box>
<Grid container spacing={0}>
<Grid p={1} item sx={{backgroundColor: 'primary.dark'}}> <Box>Item 1</Box></Grid>
<Grid p={1} item sx={{backgroundColor: 'primary.main'}}><Box>Item 2</Box></Grid>
<Grid p={1} item sx={{backgroundColor: 'primary.light'}}><Box>Item 3</Box></Grid>
</Grid>
</Box>
</Box>
Result:
Also here is the link to GitHub issue I have created: https://github.com/mui/material-ui/issues/31244
I have added background to the container and coloured the box inside the items, this provides a better idea about what is happening:
<Box component='section'>
<Typography variant='h5'>Testing Spacing</Typography>
<Box>
<Grid container spacing={2}
sx={{backgroundColor: 'secondary.main'}}
>
<Grid item> <Box sx={{backgroundColor: 'primary.dark'}}>Item 1</Box></Grid>
<Grid item><Box sx={{backgroundColor: 'primary.main'}}>Item 2</Box></Grid>
<Grid item><Box sx={{backgroundColor: 'primary.light'}}>Item 3</Box></Grid>
</Grid>
</Box>
</Box>
Result:
Solution 1:[1]
Spacing can indeed be a bit confusing with Grid
.
I usually set spacing(0)
for the Grid container and handle padding
/ margin
by the content of each Grid item
<Grid container spacing={0}>
<Grid item>
<Box p={1}>Item 1</Box> // use m={1} if you want margin
</Grid>
<Grid item>
<Box p={1}>Item 2</Box>
</Grid>
<Grid item>
<Box p={1}>Item 3</Box>
</Grid>
</Grid>
Alternatively, if you want to use spacing(2)
you can account for the spacing's offset and wrap your Grid container in a Box that manages this offset.
<Box m={xs ? -1 : -3}> // pseudo code check
<Grid container spacing={2}>
<Grid item xs={12} sm={4}>Item 1</Grid>
<Grid item xs={12} sm={4}>Item 2</Grid>
<Grid item xs={12} sm={4}>Item 3</Grid>
</Grid>
</Box>
Personally, I'm not a huge fan of this approach. I like using Grid for mobile flexibility and with the margin-offset approach, you have to keep good track of how many grid items you have per row, and then adjust the box margin based on this.
Solution 2:[2]
The behavior of the MUI grid spacing is a bit unexpected since it moves the grid items to the bottom right. To keep the grid items centered you'll need to manually add paddings to the right and bottom of the container or items. One option is simply to add the same amount of spacing as padding to the right and bottom of the grid. The drawback is that you' ll have to calculate the proper amount of padding, if your grid container itself has already a padding.
The second option is to make the grid items context aware and add right padding to the last items in a grid row when the row is full. This will still leave you with the task to calculate the proper bottom padding of the grid. It would be more intuitive if the calculations of the right and bottom paddings were done internally by the MUI grid.
However, here is a simple Wrapper component that adjusts the right padding of the outer grid items in order to center the items horizontally. You'll only have to add addtional padding at the bottom of the grid.
EDIT
Actually I realized that the intial approach with adding padding just to the last columns also changes the width of the last element. So here is a much simpler approach by overriding the MUI spacing and just add half of the spacing to the left and right of all the elements. The code becomes also much simpler.
import { Breakpoint, GridSize, GridSpacing } from '@mui/material';
import { FC, ReactElement, cloneElement } from 'react';
type GridWrapperSettings = {
spacing: GridSpacing;
columns: { [key in Breakpoint]?: GridSize };
};
export const GridWrapper: FC<GridWrapperSettings & { children?: ReactElement }> = (props) => {
if (!props.children) {
return <></>;
}
// remove MUI spacing
const grid = cloneElement(props.children, {
spacing: 0,
});
// adjust items
const items = grid.props.children.map((c) => {
return cloneElement(c, {
// assign responsive column settings
xs: props.columns.xs,
sm: props.columns.sm,
md: props.columns.md,
lg: props.columns.lg,
xl: props.columns.xl,
// assign half of the spacing on each side and a full spacing at the bottom
sx: {
pr: 0.5 * (props.spacing as number),
pl: 0.5 * (props.spacing as number),
pb: props.spacing,
},
},
});
});
return cloneElement(grid, {
children: items,
});
};
When using you only have to set the spacing and columns once in the wrapper:
<GridWrapper spacing={4} columns={{ xs: 12, md: 6}}>
<Grid
container
direction="row"
justifyContent="center"
alignItems="stretch"
>
<Grid item>My Item</Grid>
<Grid item>My Item</Grid>
</Grid>
</GridWrapper>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |