<Box>, <Stack> and <Grid>

To facilitate the creation of custom layouts, Material-UI provides three layout components that you will use all the time. It’s important that you understand how they work.

<Box>

The <Box> component serves as a wrapper component for most of the CSS utility needs. By default, it renders a <div> element.

Box

It accepts all the sx prop, which makes it easy to style:

import { Box } from '@material-ui/core';

const MyComponent = () => (
    <Box
        sx={{
          width: 300,
          height: 300,
          bgcolor: 'primary.main',
          '&:hover': {
            backgroundColor: 'primary.dark',
            opacity: [0.9, 0.8, 0.7],
          },
        }}
    >
        // ...
    </Box>
);

<Box> supports all the CSS properties as props, so you can write the same component as follows:

const MyComponent = () => (
    <Box
        width={300}
        height={300}
        bgcolor="primary.main"
        sx={{
          '&:hover': {
            backgroundColor: 'primary.dark',
            opacity: [0.9, 0.8, 0.7],
          },
        }}
    >
        // ...
    </Box>
);

You can render any component with <Box>, not only a <div>. For instance, to render a <span> with custom styles:

export default function BoxComponent() {
  return (
    <Box component="span" sx={{ p: 2, border: '1px dashed grey' }}>
      <Button>Save</Button>
    </Box>
  );
}

If you need to customize the spacing of a react-admin or a Material-UI element, use their sx prop instead of a <Box> wrapper:

// prefer
<NumberField
    source="total"
    options={{ style: 'currency', currency: 'USD' }}
    sx={{ fontWeight: 'bold' }}
/>
// to
<Box fontWeight="bold">
    <NumberField
        source="total"
        options={{ style: 'currency', currency: 'USD' }}
    />
</Box>

Tip: If you use <Box> to lay out elements with display:flex or display:grid, prefer the dedicated <Stack> and <Grid> components instead.

To learn more, read the Material-UI Box documentation.

<Stack>

<Stack> is a container component for arranging elements vertically or horizontally. Use it whenever you need to lay out elements in a column or a row.

Stack

import { Stack } from '@material-ui/core';

const Items = () => (
    <Stack spacing={2}>
        <Item>Item 1</Item>
        <Item>Item 2</Item>
        <Item>Item 3</Item>
    </Stack>
);

<Stack> renders a <div> with display:flex. It accepts any React element as child - even other <Stack> components.

<Stack> accepts all the FlexBox properties as props, so you can write layouts as follows:

<Stack
  direction="row"
  justifyContent="center"
  alignItems="center"
  spacing={2}
>

Use the spacing prop to control the space between children. The spacing value can be any number, including decimals, or a string. The prop is converted into a CSS property using the theme.spacing() helper.

<Stack spacing={2}>
  <Item>Item 1</Item>
  <Item>Item 2</Item>
  <Item>Item 3</Item>
</Stack>

By default, <Stack> arranges items vertically in a column. Use the direction prop to position items horizontally in a row:

Stack row

<Stack direction="row" spacing={2}>
  <Item>Item 1</Item>
  <Item>Item 2</Item>
  <Item>Item 3</Item>
</Stack>

Use the divider prop to insert an element between each child.

import { Stack } from '@material-ui/core';

export const DividerStack = () => (
    <div>
      <Stack
        direction="row"
        divider={
          <Box
            component="hr"
            sx={{
              border: (theme) =>
                `1px solid ${theme.palette.mode === 'dark' ? '#262B32' : '#fff'}`,
            }}
          />
        }
        spacing={2}
      >
        <Item>Item 1</Item>
        <Item>Item 2</Item>
        <Item>Item 3</Item>
      </Stack>
    </div>
);

To learn more, read the Material-UI Stack documentation.

<Grid>

<Grid> is a container component for arranging elements in a grid. It is based on a 12-column grid layout.

Grid

import Grid from '@mui/material/Grid';

export const BasicGrid = () => (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
      </Grid>
    </Box>
);

Column widths are integer values between 1 and 12; they apply at any breakpoint and indicate how many columns are occupied by the component.

A value given to a breakpoint applies to all the other breakpoints wider than it (unless overridden, as you can read later in this page). For example, xs={12} sizes a component to occupy the whole viewport width regardless of its size.

Components may have multiple widths defined, causing the layout to change at the defined breakpoint. Width values given to larger breakpoints override those given to smaller breakpoints.

For example, xs={12} sm={6} sizes a component to occupy half of the viewport width (6 columns) when viewport width is 600 or more pixels. For smaller viewports, the component fills all 12 available columns.

To control space between children, use the spacing prop. The spacing value can be any positive number, including decimals and any string. The prop is converted into a CSS property using the theme.spacing() helper.

<Grid container spacing={2}>

The rowSpacing and columnSpacing props allow for specifying the row and column gaps independently. It’s similar to the row-gap and column-gap properties of CSS Grid.

<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
  <Grid item xs={6}>
    <Item>1</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>2</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>3</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>4</Item>
  </Grid>
</Grid>

The Auto-layout makes the items equitably share the available space. That also means you can set the width of one item and the others will automatically resize around it.

<Grid container spacing={3}>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>xs=6</Item>
  </Grid>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
</Grid>

You can switch the props’ value based on the active breakpoint.

<Grid container spacing={{ xs: 2, md: 3 }} columns={{ xs: 4, sm: 8, md: 12 }}>
  {Array.from(Array(6)).map((_, index) => (
    <Grid item xs={2} sm={4} md={4} key={index}>
      <Item>xs=2</Item>
    </Grid>
  ))}
</Grid>

Responsive values is supported by:

  • columns
  • columnSpacing
  • direction
  • rowSpacing
  • spacing

Check the Material-UI Grid documentation for more information.