static/app/components/core/layout/grid.mdx
import {Container, Grid} from '@sentry/scraps/layout';
import * as Storybook from 'sentry/stories';
export const documentation = import('!!type-loader!@sentry/scraps/layout/grid');
export function CustomComponent(/** @type {Record<string, any>} */ props) { return <div {...props} />; }
export const ALIGNMENT_OPTIONS = /** @type {const} */ ([ {justify: 'start', align: 'start', label: 'start'}, {justify: 'center', align: 'center', label: 'center'}, {justify: 'end', align: 'end', label: 'end'}, {justify: 'between', align: 'stretch', label: 'between'}, {justify: 'around', align: 'stretch', label: 'around'}, {justify: 'evenly', align: 'stretch', label: 'evenly'}, ]);
The Grid component is a layout component that extends the Container component with CSS grid properties.
To create a basic grid container, wrap elements in <Grid> and define columns using columns.
<Grid columns="repeat(3, 1fr)" gap="md">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Grid>
The Grid implements composition via <a href="/stories/layout/composition">render prop</a> pattern.
<Storybook.Demo>
<Grid
areas={ "header header" "sidebar main" "footer footer"}
border="primary"
radius="md"
padding="md"
{props => (
<CustomComponent {...props}>
<Container
border="primary"
background="primary"
radius="md"
padding="md"
area="header"
>
Header
</Container>
<Container
border="primary"
background="primary"
radius="md"
padding="md"
area="sidebar"
>
Sidebar
</Container>
<Container
border="primary"
background="primary"
radius="md"
padding="md"
area="main"
>
Main Content
</Container>
<Container
border="primary"
background="primary"
radius="md"
padding="md"
area="footer"
>
Footer
</Container>
</CustomComponent>
)}
as propThe Grid component renders a div element by default, but you can specify the DOM node to render by passing a as prop.
<Grid as="section" padding="md" background="primary">
Basic grid content
</Grid>
<Storybook.Demo>
<Grid
areas={ "header header" "sidebar main" "footer footer"}
columns="100px 1fr"
rows="60px 1fr 60px"
gap="md"
padding="md"
height="300px"
<Container
area="header"
border="primary"
padding="md"
background="primary"
radius="md"
>
Header
</Container>
<Container
area="sidebar"
border="primary"
padding="md"
background="primary"
radius="md"
>
Sidebar
</Container>
<Container
area="main"
border="primary"
padding="md"
minWidth="300px"
background="primary"
radius="md"
>
Main Content
</Container>
<Container
area="footer"
border="primary"
padding="md"
background="primary"
radius="md"
>
Footer
</Container>
Grid provides fine-grained control over alignment using justify, align, justifyItems, and alignContent.
<Storybook.Demo> <Grid columns="repeat(1, 1fr)" gap="md" padding="md" width="100%"> {ALIGNMENT_OPTIONS.map(({justify, align, label}) => ( <Grid key={label} columns="repeat(2, 25%)" gap="sm" justify={justify} align={align}> <Container padding="md" background="primary" radius="md" border="primary"> {label} </Container> <Container padding="md" background="primary" radius="md" border="primary"> alignment </Container> </Grid> ))} </Grid> </Storybook.Demo>
<Grid columns="repeat(2, 1fr)" justify="center" align="center">
<div>Centered Item</div>
<div>Another Item</div>
</Grid>
All props support responsive values using breakpoint objects. Breakpoints are: xs, sm, md, lg, xl, 2xl.
Example of a responsive grid container that changes from single column on small screens to multiple columns on larger screens.
<Storybook.Demo> <Grid columns={{xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)'}} gap="md" padding="md"
<Container padding="md" border="primary" radius="md" background="primary">
Responsive
</Container>
<Container padding="md" border="primary" radius="md" background="primary">
Grid
</Container>
<Container padding="md" border="primary" radius="md" background="primary">
Layout
</Container>
<Container padding="md" border="primary" radius="md" background="primary">
Items
</Container>
<Container padding="md" border="primary" radius="md" background="primary">
🔥
</Container>
<Container padding="md" border="primary" radius="md" background="primary">
Awesome
</Container>
If a prop is not specified for a breakpoint, the value will not be inherited from the previous breakpoint.