The Ultimate Guide to the New MUI Stack Component

Material-UI (now MUI) has a variety of excellent layout components. The Stack component is new in version 5 and was created to easily handle one-dimensional vertical and horizontal layouts. Previously these were often handled with the Box component using a flex layout, or a Grid component, but Grids were intended for 2-d layouts.

One of the most important features of the Stack component is that it is a “CSS Utility Component”. This means that quick styling systems are available via simple props such as gap, width, and mt (margin-top). I’ll demo several of these below.

We’ll also explore the classes available for styling the Stack component. A Code Sandbox link with full React code is available in the Resources section.

Here’s a YouTube version of this post or you can watch the video below:

The Ultimate Guide to the New MUI S...
The Ultimate Guide to the New MUI Stack Component

Stack Props and API

The Stack component has lots of spacing and layout props available. It also has access to a styling prop called sx, (Read a full guide to the new sx styling prop here). Understanding these props will allow you to use the Stack component to its fullest potential.

A colorful MUI Stack component
import * as React from "react";
import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
import { styled } from "@mui/material/styles";
//import { makeStyles } from "@mui/styles";

//makeStyles method of styling.  I used sx instead, code is almost the same
// const useStyles = makeStyles({
//   root: {
//     backgroundColor: "gray",
//     //borderRadius: 5,
//     "&.MuiPaper-root": {
//       border: "1px solid black"
//     },
//     "& :first-child": {
//       //backgroundColor: "red"
//     }
//   }
// });

const sxStyles = {
  backgroundColor: "gray",
  //borderRadius: 5,
  "&.MuiPaper-root": {
    border: "1px solid black"
  },
  "& :first-child": {
    //backgroundColor: "red"
  }
};

const Item = styled(Paper)(({ theme }) => ({
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: "center",
  color: theme.palette.text.secondary
}));

export default function ResponsiveStack() {
  //const classes = useStyles();
  return (
    <div style={{ width: "50%", margin: "auto" }}>
      <Stack
        direction={{ xs: "column-reverse", md: "row" }}
        component={Paper}
        spacing={{ xs: 2, md: 4 }}
        divider={
          <div style={{ width: "100%", height: 1, backgroundColor: "black" }} />
        }
        //gap={2}
        //width={120}
        //className={classes.root}
        sx={{
          backgroundColor: "primary.main",
          borderRadius: 1,
          gap: { xs: 2, md: 4 },
          ...sxStyles
        }}
      >
        <Item>Item 1</Item>
        <Item>Item 2</Item>
        <Item>Item 3</Item>
      </Stack>
      <div style={{ marginTop: 24 }}>
        <a
          target="_blank"
          href="https://smartdevpreneur.com/the-ultimate-guide-to-the-new-mui-stack-component/"
        >
          Here's how to use MUI's new Stack component
        </a>
      </div>
    </div>
  );
}

The direction prop may most commonly be used to set a row (horizontal) and column (vertical) layout. However, it has additional values such as column-reverse, which I use above. It also has a clever “built-in” way to use theme breakpoint values, which you can see in my code above. A list of possible values is pictured below. “Column” is the default.

The component prop is used to change the root element rendered by the Stack component. The default is div. I show an example of passing in a Paper component later on in the styling section. It changes the root div to Paper, which means in the DOM MUI has rendered the element and classes that comprise a “Paper” component.

The divider prop is similar to the component prop, except that it controls what element is rendered in the DOM between the Stack’s children components. In my code above I passed in a custom styled div. A common choice is to pass in a MUI Divider component.

MUI Stack Spacing

The remaining prop listed in the docs is spacing. It can be passed either inside the sx prop or on its own. Additionally, I passed gap and width as their own props instead of inside sx. These last two were not listed in the docs but are available.

  • The spacing prop adds padding to the children items. It will automatically either be top and bottom padding or left and right padding depending on the direction prop value.
  • The gap prop adds a CSS row-gap or column-gap value (see the dev tools screenshot below).
  • The width prop is simply a quick way to set width. You likely don’t want to add the width prop if the direction might flip to row based on breakpoints.

The spacing prop is clever enough to only add margin to child items after the first child . Take a look at the CSS in the DOM for the demo I made. My example uses value direction={{ xs: "column-reverse"}}, so the third child item (highlighted below) is actually rendered at the top and MUI adds a marginBottom value.

This presents a challenge when we try to wrap items that overflow the Stack. Later in this post I have a solution for that issue.

MUI Stack Horizontal Layout

If you need a horizontal layout, simply set the direction prop to “row”. The default direction value is “column” which produces the vertical layout seen in the last section.

Here is a screenshot of the Stack with a horizontal layout:

MUI Stack Horizontal
MUI Stack Horizontal

Here is example code that sets direction to column on the smallest screens and row on all other sizes:

direction={{ xs: "column", sm: "row" }}

Background Color and Border Radius with the Stack sx Prop

The sx prop is a quick way to pass any valid CSS. It can also be used with the MUI spacing system to pass shorthand spacing props. It even has access to theme values that can be used with valid CSS attributes.

I used the sx prop to pass background color and border radius: sx={{ backgroundColor: "primary.main", borderRadius: 2 }}. Keep in mind that styling via className will override styling from the sx prop.

MUI Stack Wrap

There is a known issue in the Stack component where it does not wrap by default when the items inside overflow the width of the component. The MUI team even created this github issue to track the ‘problem’. As far as I can tell, they decided to leave it with no wrap by default since this is an ambiguous area of web design.

If you want contents to wrap, here’s one solution

  • flexWrap: “wrap” in the Stack sx prop
  • spacing={0} in the Stack
  • Manually add marginLeft on the items that don’t touch the left edge of the Stack
MUI Stack Wrap Example
I fixed this CodeSandbox example from the MUI issue using MUI v5: flexWrap and manual spacing

The challenge is: if you add spacing via the spacing prop, you have to select the appropriate child items with a tricky nested selector and remove their marginLeft. In this case, that would have been the last item. It’s not impossible, but I think manually controlling margin might be easier.

Stack Styling and Classes

The Stack component by default has minimal styling applied. The styling focuses on flexing in a row or column direction. If you want to apply more default styling, set prop component={Paper} and you’ll get a nice shadowing effect plus some borders.

A simple way to style the Stack component is by adding styling values with the sx prop. You can also still use makeStyles and the className prop.

const sxStyles = {
  backgroundColor: "gray",
  //borderRadius: 5,
  "&.MuiPaper-root": {
    border: "1px solid black"
  },
  "& :first-child": {
    backgroundColor: "red"
  }
};

//JSX
<Stack
  sx={{
    backgroundColor: "primary.main",
    borderRadius: 1,
    gap: { xs: 2, md: 4 },
    ...sxStyles
  }}
>

Here I’ve added a grey background color to Stack, plus styled the first child with a red background. In older minor versions of MUI v5, there was no .MuiStack class (see the screenshot below), but I think that newer minor versions have changed that.

No default class on MUI Stack

A way to add a default class for styling purposes is to use the component prop. For example, if I add component={Paper} then the DOM updates to include Paper default classes:

MUI Stack vs MUI Grid

When choosing between the Stack component and the Grid component, there are several considerations. Do you need:

  • One dimensional (row or column) or two dimensional (row and column) layout?
  • A simple wrapper or one that has subcomponents and customizations?
  • An extremely light DOM or can it be heavier on divs?

In each point above, the first benefit was for the Stack component, the second benefit was for the Grid.

Exploring these in depth, we learned in this post that the Stack handles 1D layouts. The Grid is meant for 2D layouts. That alone will help you choose which to use.

On the second point, the Stack renders as a simple div. The Grid potentially has several layers of divs. The Grid usually contains (at a minimum) a Grid Container component and Grid Item components that wrap the actual content.

It follows from this DOM heaviness that the Stack renders faster, but the Grid can position contents with more customization and flexibility. Take a look at this post to see exactly how to position contents within a Grid.

MUI Stack vs MUI Box

The Material-UI Stack component has replaced the Box component, in my opinion.

The Box is described as a wrapper component for CSS utility needs by the MUI docs. However, all the styling properties and shortcuts available on the Box are also available for the Stack. The Box is equivalent to a Stack with default prop values.

Additionally, the Stack component is designed specifically to control 1-dimensional layouts. This means it can do everything the Box can, plus it has functionality to easily control vertical and horizontal layouts.

FAQs

What is spacing in MUI?

Some MUI components have a spacing prop that adds margin or padding. The screenshot below shows the resulting margin-top from <Stack spacing={2}/>.
What is MUI spacing

How do you add spacing in Material-UI?

You can add spacing to any component using margin or padding. Here’s example code: <Button sx={{margin: '2px', padding: '2px'}}>Spaced Button</Button>
Some components have a special spacing prop. The spacing prop behaves differently on different components. For example, on the Stack component spacing adds margin-top, while Grid spacing adds padding-top and padding-left.

How do you align content to the right in Material-UI?

Here are a few different methods to right align content in MUI:
1. Use justify-content: “flex-end”
2. Use margin-left: “auto”
3. Use the display and justifyContent props – depends on the component
The first two options above can be used inside the sx prop or with the styled API. Be sure to use JSX syntax.
Here is an example of the third option where the MUI Stack component uses alignment props:
<Stack display="flex" justifyContent="flex-end"/>

Resources

Code Sandbox Link

Stack API docs

Stack component docs

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.