Skip to main content

Layout

Layout components enable the creation of composable layouts. The main guiding principle is that space between elements "belongs" to their container. In other words, components never define any space outside their own boundaries. This allows for precise control of the spacing and makes components truly re-usable in different spacing contexts.

The design system provides a set of layout components, that can be arbitrarily nested inside each other to create complex layouts:

  • Stack
  • Inline
  • Columns
  • Inset
  • ContentBlock
Credits

🙏 The design of Layout components is heavily inspired by the Braid Design System and the Rainbow Design System

Spacing

The design system defines a standard spacing scale which applies across all components. Valid values are:

0
4
8
12
16
24
32
40
80

Stack

Stack is a layout component that arranges its children vertically.

<Stack space={32}>
<Placeholder />
<Placeholder />
<Placeholder />
</Stack>

You can control the vertical space between children with the space prop, which accepts finite set of values as defined by the spacing scale.

Stack can also control the horizontal alignment of its children with the align prop:

<Stack space={32} align="center">
<Placeholder width={200} />
<Placeholder width={200} />
<Placeholder width={200} />
</Stack>

The space and the align props also supports defining their values depending on the breakpoint. For example, you can define different align values on desktop and on mobile:

<Stack
space={32}
align={{
desktop: "right",
tablet: "center",
}}
>
<Placeholder width={200} />
<Placeholder width={200} />
<Placeholder width={200} />
</Stack>
tip

Try resizing the browser window to see how the alignment changes.

info

If you specify only some breakpoints, e.g. mobile and desktop, they will "inherit" from the breakpoint immediately "above". For example, if you specify mobile and desktop, the tablet breakpoint will inherit from the desktop value.

Stack can also optionally render horizontal dividers in between its children using the dividers prop:

<Stack space={32} dividers>
<Placeholder />
<Placeholder />
<Placeholder />
</Stack>

Inline

Inline can be used to create horizontally flowing layouts, which wrap across multiple lines if necessary.

<Inline space={24}>
<Placeholder width={200} />
<Placeholder width={100} />
<Placeholder width={300} />
</Inline>

The spacing between children can be controlled with the space prop, which is also applied between rows.

Inline can control the horizontal and vertical alignment of its children with the align and alignY props respectively.

<Inline space={24} align="center" alignY="bottom">
<Placeholder width={200} height={50} />
<Placeholder width={100} height={200} />
<Placeholder width={300} height={150} />
</Inline>

Similarly to Stack, space, align and alignY can be defined depending on the breakpoint:

<Inline
space={24}
align={{
desktop: "right",
tablet: "center",
}}
alignY="bottom"
>
<Placeholder width={100} />
<Placeholder width={200} />
<Placeholder width={100} />
</Inline>
tip

Try resizing the browser window to see how the alignment changes.

Inline can also automatically collapse its children into a single column when the screen is below a certain breakpoint. This is achieved using the collapseBelow property.

Here's an example of a layout where the children are collapsed and centered only on mobile:

<Inline
space={24}
collapseBelow="tablet"
align={{
mobile: "center",
}}
>
<Placeholder width={100} />
<Placeholder width={200} />
<Placeholder width={100} />
</Inline>

Inline can also render its children in reverse dom order: this may be useful in case you want to preserve the DOM order for accessibility (e.g. tabbing using a keyboard respects DOM order) but reverse the elements visually. For this you can use the reverse prop:

1
2
3
<Inline space={24} reverse>
<Placeholder label="1" width={100} />
<Placeholder label="2" width={100} />
<Placeholder label="3" width={100} />
</Inline>

The reverse prop is also responsive, so you can apply the reverse visual ordering only for certain breakpoints, if needed.

Columns

Columns is used to create horizontal layouts with a larger degree of flexibility with respect to Inline.

<Columns space={24}>
<Placeholder height={200} />
<Placeholder height={200} />
</Columns>

Columns share the space evenly by default, but it's possible to control the width of individual columns by using the Column component.

For example, here's a three-column layout where the two side columns occupy 1/5 of the available space each and the central column takes up the remaining space:

1/5
1/5
<Columns space={24}>
<Column width="1/5">
<Placeholder height={200} label="1/5" />
</Column>
<Placeholder height={200} />
<Column width="1/5">
<Placeholder height={200} label="1/5" />
</Column>
</Columns>
tip

Using Column without any props is equivalent to just passing its children directly.

Columns can also be sized according to their content, which is useful when you want a column to be as small as possible:

I'm a content-sized column
<Columns space={24}>
<Column width="content">
<Placeholder height={200} label="I'm a content-sized column" />
</Column>
<Placeholder height={200} />
</Columns>

Similarly to Inline, Columns can also control the horizontal and vertical alignment of columns:

<Columns space={24} alignY="bottom">
<Placeholder height={50} />
<Placeholder height={100} />
</Columns>

And again, space, align and alignY can be defined depending on the breakpoint and collapseBelow can be used to arrange columns vertically below a certain screen size:

<Columns
space={24}
alignY="bottom"
collapseBelow="desktop"
align={{
mobile: "center",
desktop: "left",
}}
>
<Placeholder height={100} />
<Placeholder height={100} />
<Placeholder height={100} />
</Columns>

Columns supports the same reverse property as Inline. This is particularly usefor for implementing layouts where you have columns that you want to collapse in reverse DOM order. Here's an example where the sidebar moves above the main content when collapsing below the desktop breakpoint:

sidebar
<Columns
space={24}
collapseBelow="desktop"
reverse={{
tablet: true,
mobile: false,
}}
>
<Placeholder background="softJade" />
<Column
width={{
desktop: "content",
tablet: "full",
mobile: "full",
}}
>
<Placeholder label="sidebar" background="softBlue" />
</Column>
</Columns>

Tiles

Sometimes you may need to control the number of columns but also allow wrapping, to create grid-like layouts. This can't be achieved with Inline (becuase it doesn't control the number of columns), nor Columns (because it does not allow wrapping).

In such cases, you can use the Tiles component, which lays out its children in a fixed number of columns, wrapping if necessary:

<Tiles space={24} columns={3}>
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
</Tiles>

The column and space props can be set responsively, so you can adapt the layout based on the active breakpoint. For example, here's how to render 4 columns on desktop, 2 on tablet and 1 on mobile:

<Tiles
space={{
mobile: 8,
tablet: 16,
desktop: 32,
wide: 32,
}}
columns={{
mobile: 1,
tablet: 2,
desktop: 4,
wide: 6,
}}
>
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
<Placeholder />
</Tiles>

Inset

Inset is used to create a container with equal padding on each side:

<Box
background="softYellow"
style={{
width: "fit-content",
}}
>
<Inset space={16}>
<Placeholder width={200} />
</Inset>
</Box>

Horizontal and vertical padding can be set independently using the spaceX and spaceY props:

<Box
background="softYellow"
style={{
width: "fit-content",
}}
>
<Inset spaceX={40} spaceY={16}>
<Placeholder width={200} />
</Inset>
</Box>

ContentBlock

All components span the entire width of their container by default. In some cases, though, you may want to cap their width: this is usually the case when working with page layouts or with long text paragraphs.

In such cases, you can use ContentBlock to limit the maxWidth and optionally center the content in the parent container.

For example, here's how to limit the width of long a paragraph of text to 700px, so that it stays readable:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam eget laoreet purus. Etiam hendrerit nibh id turpis aliquam, id ultrices metus viverra. Pellentesque elementum eros et varius consequat. Aliquam erat volutpat. Ut quis felis tincidunt, mollis lectus ut, commodo est. Nulla id sapien aliquam, faucibus nibh in, suscipit lorem. Integer pharetra pharetra turpis eu sodales. Maecenas in rutrum velit. Suspendisse non odio tortor. Etiam in euismod erat, eget lacinia erat. Nunc non pellentesque nunc, quis aliquam purus. Morbi dui mi, dignissim et turpis non, tempus facilisis erat. Phasellus nibh ante, lobortis vel purus maximus, tempus imperdiet nisl. Integer venenatis metus sit amet sapien blandit, eu volutpat magna mollis. Donec ac dui neque. Donec id pharetra ante, in faucibus neque. Nam sit amet felis viverra urna consequat venenatis ac at leo. Fusce tincidunt pretium elit, vel efficitur est molestie ut. Donec at erat tellus. Nam convallis, ex vel luctus consectetur, quam quam laoreet arcu, a auctor mi mi sit amet magna. Etiam viverra nec tellus at pulvinar. Integer purus lacus, gravida a lacinia sed, rutrum quis erat. Duis at purus ut ipsum lobortis condimentum eu volutpat lorem. Donec et eros non nisi fringilla bibendum. Morbi porttitor id eros at pellentesque. Etiam quis risus a ante tristique sollicitudin id sit amet nisl. Nunc consequat semper dui id posuere. In sodales lorem turpis, quis consequat ex imperdiet a. Aliquam rutrum pellentesque dui, sed dictum ante lacinia nec. Sed ac magna augue.
<ContentBlock maxWidth={700}>
<Body size="large">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam eget
laoreet purus. Etiam hendrerit nibh id turpis aliquam, id ultrices metus
viverra. Pellentesque elementum eros et varius consequat. Aliquam erat
volutpat. Ut quis felis tincidunt, mollis lectus ut, commodo est. Nulla id
sapien aliquam, faucibus nibh in, suscipit lorem. Integer pharetra pharetra
turpis eu sodales. Maecenas in rutrum velit. Suspendisse non odio tortor.
Etiam in euismod erat, eget lacinia erat. Nunc non pellentesque nunc, quis
aliquam purus. Morbi dui mi, dignissim et turpis non, tempus facilisis erat.
Phasellus nibh ante, lobortis vel purus maximus, tempus imperdiet nisl.
Integer venenatis metus sit amet sapien blandit, eu volutpat magna mollis.
Donec ac dui neque. Donec id pharetra ante, in faucibus neque. Nam sit amet
felis viverra urna consequat venenatis ac at leo. Fusce tincidunt pretium
elit, vel efficitur est molestie ut. Donec at erat tellus. Nam convallis, ex
vel luctus consectetur, quam quam laoreet arcu, a auctor mi mi sit amet
magna. Etiam viverra nec tellus at pulvinar. Integer purus lacus, gravida a
lacinia sed, rutrum quis erat. Duis at purus ut ipsum lobortis condimentum
eu volutpat lorem. Donec et eros non nisi fringilla bibendum. Morbi
porttitor id eros at pellentesque. Etiam quis risus a ante tristique
sollicitudin id sit amet nisl. Nunc consequat semper dui id posuere. In
sodales lorem turpis, quis consequat ex imperdiet a. Aliquam rutrum
pellentesque dui, sed dictum ante lacinia nec. Sed ac magna augue.
</Body>
</ContentBlock>

Another example is capping the maxWidth of the entire page content, and centering it:

<ContentBlock maxWidth={700} alignSelf="center">
<Columns space={80}>
<Placeholder />
<Placeholder />
</Columns>
</ContentBlock>