Stack
Stack is a container component for arranging elements vertically or horizontally.
Introduction
The Stack component manages the layout of its immediate children along the vertical or horizontal axis, with optional spacing and dividers between each child.
Basics
import Stack from '@mui/system/Stack';
The Stack component acts as a generic container, wrapping around the elements to be arranged.
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.)
import Box from '@mui/system/Box';
import Stack from '@mui/system/Stack';
import { styled } from '@mui/system';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function BasicStack() {
return (
<Box sx={{ width: '100%' }}>
<Stack spacing={2}>
<Item>Item 1</Item>
<Item>Item 2</Item>
<Item>Item 3</Item>
</Stack>
</Box>
);
}
Stack vs. Grid
Stack is concerned with one-dimensional layouts, while Grid handles two-dimensional layouts. The default direction is column which stacks children vertically.
Direction
By default, Stack arranges items vertically in a column.
Use the direction prop to position items horizontally in a row:
import Stack from '@mui/system/Stack';
import { styled } from '@mui/system';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function DirectionStack() {
return (
<div>
<Stack direction="row" spacing={2}>
<Item>Item 1</Item>
<Item>Item 2</Item>
<Item>Item 3</Item>
</Stack>
</div>
);
}
Dividers
Use the divider prop to insert an element between each child, as shown below:
import Box from '@mui/system/Box';
import Stack from '@mui/system/Stack';
import { styled } from '@mui/system';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function DividerStack() {
return (
<div>
<Stack
direction="row"
divider={
<Box
component="hr"
sx={(theme) => ({
border: `1px solid ${'#fff'}`,
...theme.applyStyles('dark', {
border: `1px solid ${'#262B32'}`,
}),
})}
/>
}
spacing={2}
>
<Item>Item 1</Item>
<Item>Item 2</Item>
<Item>Item 3</Item>
</Stack>
</div>
);
}
Responsive values
You can switch the direction or spacing values based on the active breakpoint.
import Stack from '@mui/system/Stack';
import { styled } from '@mui/system';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function ResponsiveStack() {
return (
<div>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={{ xs: 1, sm: 2, md: 4 }}
>
<Item>Item 1</Item>
<Item>Item 2</Item>
<Item>Item 3</Item>
</Stack>
</div>
);
}
Flexbox gap
To use flexbox gap for the spacing implementation, set the useFlexGap prop to true.
It removes the known limitations of the default implementation that uses CSS nested selector. However, CSS flexbox gap is not fully supported in some browsers.
We recommend checking the support percentage before using it.
import Stack from '@mui/system/Stack';
import Box from '@mui/system/Box';
import { styled } from '@mui/system';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
flexGrow: 1,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function FlexboxGapStack() {
return (
<Box sx={{ width: 200 }}>
<Stack
spacing={{ xs: 1, sm: 2 }}
direction="row"
useFlexGap
sx={{ flexWrap: 'wrap' }}
>
<Item>Item 1</Item>
<Item>Item 2</Item>
<Item>Long content</Item>
</Stack>
</Box>
);
}
Interactive demo
Below is an interactive demo that lets you explore the visual results of the different settings:
<Stack
direction="row"
spacing={2}
sx={{
justifyContent: "center",
alignItems: "center",
}}
>import * as React from 'react';
import FormControl from '@mui/material/FormControl';
import FormLabel from '@mui/material/FormLabel';
import FormControlLabel from '@mui/material/FormControlLabel';
import Paper from '@mui/material/Paper';
import RadioGroup from '@mui/material/RadioGroup';
import Radio from '@mui/material/Radio';
import Grid from '@mui/system/Grid';
import Stack from '@mui/system/Stack';
import type { StackProps } from '@mui/system/Stack';
import { styled } from '@mui/system';
import { HighlightedCode } from '@mui/internal-core-docs/HighlightedCode';
const Item = styled('div')(({ theme }) => ({
backgroundColor: '#fff',
padding: theme.spacing(1),
textAlign: 'center',
borderRadius: 4,
...theme.applyStyles('dark', {
backgroundColor: '#262B32',
}),
}));
export default function InteractiveStack() {
const [direction, setDirection] = React.useState<StackProps['direction']>('row');
const [justifyContent, setJustifyContent] = React.useState('center');
const [alignItems, setAlignItems] = React.useState('center');
const [spacing, setSpacing] = React.useState(2);
const jsx = `
<Stack
direction="${direction}"
spacing={${spacing}}
sx={{
justifyContent: "${justifyContent}",
alignItems: "${alignItems}",
}}
>
`;
return (
<Stack sx={{ flexGrow: 1 }}>
<Stack
direction={direction}
spacing={spacing}
sx={{ justifyContent, alignItems, height: 240 }}
>
{[0, 1, 2].map((value) => (
<Item key={value} sx={{ p: 2, pt: value + 1, pb: value + 1 }}>
{`Item ${value + 1}`}
</Item>
))}
</Stack>
<Paper sx={{ p: 2 }}>
<Grid container spacing={3}>
<Grid size={12}>
<FormControl component="fieldset">
<FormLabel component="legend">direction</FormLabel>
<RadioGroup
row
name="direction"
aria-label="direction"
value={direction}
onChange={(event) => {
setDirection(event.target.value as StackProps['direction']);
}}
>
<FormControlLabel value="row" control={<Radio />} label="row" />
<FormControlLabel
value="row-reverse"
control={<Radio />}
label="row-reverse"
/>
<FormControlLabel
value="column"
control={<Radio />}
label="column"
/>
<FormControlLabel
value="column-reverse"
control={<Radio />}
label="column-reverse"
/>
</RadioGroup>
</FormControl>
</Grid>
<Grid size={12}>
<FormControl component="fieldset">
<FormLabel component="legend">alignItems</FormLabel>
<RadioGroup
row
name="alignItems"
aria-label="align items"
value={alignItems}
onChange={(event) => {
setAlignItems(event.target.value);
}}
>
<FormControlLabel
value="flex-start"
control={<Radio />}
label="flex-start"
/>
<FormControlLabel
value="center"
control={<Radio />}
label="center"
/>
<FormControlLabel
value="flex-end"
control={<Radio />}
label="flex-end"
/>
<FormControlLabel
value="stretch"
control={<Radio />}
label="stretch"
/>
<FormControlLabel
value="baseline"
control={<Radio />}
label="baseline"
/>
</RadioGroup>
</FormControl>
</Grid>
<Grid size={12}>
<FormControl component="fieldset">
<FormLabel component="legend">justifyContent</FormLabel>
<RadioGroup
row
name="justifyContent"
aria-label="justifyContent"
value={justifyContent}
onChange={(event) => {
setJustifyContent(event.target.value);
}}
>
<FormControlLabel
value="flex-start"
control={<Radio />}
label="flex-start"
/>
<FormControlLabel
value="center"
control={<Radio />}
label="center"
/>
<FormControlLabel
value="flex-end"
control={<Radio />}
label="flex-end"
/>
<FormControlLabel
value="space-between"
control={<Radio />}
label="space-between"
/>
<FormControlLabel
value="space-around"
control={<Radio />}
label="space-around"
/>
<FormControlLabel
value="space-evenly"
control={<Radio />}
label="space-evenly"
/>
</RadioGroup>
</FormControl>
</Grid>
<Grid size={12}>
<FormControl component="fieldset">
<FormLabel component="legend">spacing</FormLabel>
<RadioGroup
row
name="spacing"
aria-label="spacing"
value={spacing.toString()}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setSpacing(Number((event.target as HTMLInputElement).value));
}}
>
{[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => (
<FormControlLabel
key={value}
value={value.toString()}
control={<Radio />}
label={value}
/>
))}
</RadioGroup>
</FormControl>
</Grid>
</Grid>
</Paper>
<HighlightedCode code={jsx} language="jsx" />
</Stack>
);
}
sx prop
Use the sx prop to quickly customize any Stack instance using a superset of CSS that has access to all the style functions and theme-aware properties exposed in the MUI System package.
Below is an example of how to apply center align items using this prop:
<Stack sx={{ alignItems: 'center' }} />
Limitations
Margin on the children
Customizing the margin on the children is not supported by default.
For instance, the top-margin on the button component below will be ignored.
<Stack>
<button style={{ marginTop: '30px' }}>...</button>
</Stack>
white-space: nowrap
The initial setting on flex items is min-width: auto.
This causes a positioning conflict when children use white-space: nowrap;.
You can reproduce the issue with:
<Stack direction="row">
<span style={{ whiteSpace: 'nowrap' }}>
In order for the item to stay within the container you need to set min-width: 0.
<Stack direction="row" sx={{ minWidth: 0 }}>
<span style={{ whiteSpace: 'nowrap' }}>
Anatomy
The Stack component is composed of a single root <div> element:
<div class="MuiStack-root">
<!-- Stack contents -->
</div>