UNPKG

@mui/material

Version:

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.

641 lines (536 loc) • 19 kB
--- productId: material-ui title: React Stack component components: Stack, PigmentStack githubLabel: 'component: Stack' githubSource: packages/mui-material/src/Stack --- # 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. :::info Stack is ideal for one-dimensional layouts, while Grid is preferable when you need both vertical _and_ horizontal arrangement. ::: ## Basics ```jsx import Stack from '@mui/material/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()`](/material-ui/customization/spacing/) helper.) ```tsx import Box from '@mui/material/Box'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); 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](/material-ui/react-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: ```tsx import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); 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. This works particularly well with the [Divider](/material-ui/react-divider/) component, as shown below: ```tsx import Divider from '@mui/material/Divider'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); export default function DividerStack() { return ( <div> <Stack direction="row" divider={<Divider orientation="vertical" flexItem />} 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. ```tsx import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); 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`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/gap) for the spacing implementation, set the `useFlexGap` prop to true. It removes the [known limitations](#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](https://caniuse.com/?search=flex%20gap) before using it. ```tsx import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import Box from '@mui/material/Box'; import { styled } from '@mui/material/styles'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, flexGrow: 1, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); 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> ); } ``` To set the prop to all stack instances, create a theme with default props: ```js import { ThemeProvider, createTheme } from '@mui/material/styles'; import Stack from '@mui/material/Stack'; const theme = createTheme({ components: { MuiStack: { defaultProps: { useFlexGap: true, }, }, }, }); function App() { return ( <ThemeProvider theme={theme}> <Stack>…</Stack> {/* uses flexbox gap by default */} </ThemeProvider> ); } ``` ## Interactive demo Below is an interactive demo that lets you explore the visual results of the different settings: ```tsx import * as React from 'react'; import FormControl from '@mui/material/FormControl'; import FormLabel from '@mui/material/FormLabel'; import FormControlLabel from '@mui/material/FormControlLabel'; import Grid from '@mui/material/Grid'; import Paper from '@mui/material/Paper'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import Stack, { StackProps } from '@mui/material/Stack'; import { HighlightedCode } from '@mui/internal-core-docs/HighlightedCode'; 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) => ( <Paper key={value} sx={(theme) => ({ p: 2, pt: value + 1, pb: value + 1, color: 'text.secondary', typography: 'body2', backgroundColor: '#fff', ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })} > {`Item ${value + 1}`} </Paper> ))} </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> ); } ``` ## Customization Use the [`sx` prop](/system/getting-started/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: ```jsx <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. ```jsx <Stack> <Button sx={{ marginTop: '30px' }}>...</Button> </Stack> ``` :::success To overcome this limitation, set [`useFlexGap`](#flexbox-gap) prop to true to switch to CSS flexbox gap implementation. You can learn more about this limitation by visiting this [RFC](https://github.com/mui/material-ui/issues/33754). ::: ### 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: ```jsx <Stack direction="row"> <Typography noWrap> ``` In order for the item to stay within the container you need to set `min-width: 0`. ```jsx <Stack direction="row" sx={{ minWidth: 0 }}> <Typography noWrap> ``` ```tsx import Avatar from '@mui/material/Avatar'; import Box from '@mui/material/Box'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; const Item = styled(Paper)(({ theme }) => ({ backgroundColor: '#fff', ...theme.typography.body2, padding: theme.spacing(1), textAlign: 'center', color: (theme.vars ?? theme).palette.text.secondary, maxWidth: 400, ...theme.applyStyles('dark', { backgroundColor: '#1A2027', }), })); const message = `Truncation should be conditionally applicable on this long line of text as this is a much longer line than what the container can support.`; export default function ZeroWidthStack() { return ( <Box sx={{ flexGrow: 1, overflow: 'hidden', px: 3 }}> <Item sx={{ my: 1, mx: 'auto', p: 2 }}> <Stack spacing={2} direction="row" sx={{ alignItems: 'center' }}> <Avatar>W</Avatar> <Typography noWrap>{message}</Typography> </Stack> </Item> <Item sx={{ my: 1, mx: 'auto', p: 2 }}> <Stack spacing={2} direction="row" sx={{ alignItems: 'center' }}> <Stack> <Avatar>W</Avatar> </Stack> <Stack sx={{ minWidth: 0 }}> <Typography noWrap>{message}</Typography> </Stack> </Stack> </Item> </Box> ); } ``` ## Anatomy The Stack component is composed of a single root `<div>` element: ```html <div class="MuiStack-root"> <!-- Stack contents --> </div> ``` # PigmentStack API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Stack](https://mui.com/material-ui/react-stack/) ## Import ```jsx import PigmentStack from '@mui/material/PigmentStack'; // or import { PigmentStack } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | children | `node` | - | No | | | direction | `'column-reverse' \| 'column' \| 'row-reverse' \| 'row' \| Array<'column-reverse' \| 'column' \| 'row-reverse' \| 'row'> \| { lg?: 'column-reverse' \| 'column' \| 'row-reverse' \| 'row', md?: 'column-reverse' \| 'column' \| 'row-reverse' \| 'row', sm?: 'column-reverse' \| 'column' \| 'row-reverse' \| 'row', xl?: 'column-reverse' \| 'column' \| 'row-reverse' \| 'row', xs?: 'column-reverse' \| 'column' \| 'row-reverse' \| 'row' }` | `'column'` | No | | | divider | `node` | - | No | | | spacing | `Array<number \| string> \| number \| { lg?: number \| string, md?: number \| string, sm?: number \| string, xl?: number \| string, xs?: number \| string } \| string` | `0` | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | > **Note**: The `ref` is forwarded to the root element. ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/PigmentStack/PigmentStack.tsx](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/PigmentStack/PigmentStack.tsx) # Stack API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Stack](https://mui.com/material-ui/react-stack/) ## Import ```jsx import Stack from '@mui/material/Stack'; // or import { Stack } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | children | `node` | - | No | | | component | `elementType` | - | No | | | direction | `'column-reverse' \| 'column' \| 'row-reverse' \| 'row' \| Array<'column-reverse' \| 'column' \| 'row-reverse' \| 'row'> \| object` | `'column'` | No | | | divider | `node` | - | No | | | spacing | `Array<number \| string> \| number \| object \| string` | `0` | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | | useFlexGap | `bool` | `false` | No | | > **Note**: The `ref` is forwarded to the root element (HTMLDivElement). > Any other props supplied will be provided to the root element (native element). ## Theme default props You can use `MuiStack` to change the default props of this component with the theme. ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/Stack/Stack.js](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/Stack/Stack.js)