Layout

The guiding principle for layout in Braid is that components should not provide surrounding white space. Instead, spacing between elements is owned entirely by layout components. This approach ensures that the system is as composable as possible while keeping white space completely predictable.
All of the components referenced below can be infinitely nested within each other to create a wide variety of standard layouts. Getting a firm grasp of these components is an essential part of working effectively with Braid.
Braid provides a standard white space scale that is available across the entire component suite. As much as possible, Braid tries to make use of this scale rather than generating custom spacing rules.
none
gutter
xxsmall
xsmall
small
medium
large
xlarge
xxlarge
xxxlarge
Box is the most low-level layout component provided by Braid. Its job is to render an individual element on the screen.
In terms of page layout, Box most notably provides a set of padding options which can be used to create container elements with internal spacing.
  • padding
  • paddingX
  • paddingY
  • paddingTop
  • paddingBottom
  • paddingLeft
  • paddingRight
These options accept a value from our white space scale.
For example, if you wanted to create a container element with small spacing on all sides:
Lorem ipsum dolor sit amet.
<Box padding="small">
  <Text>Lorem ipsum dolor sit amet.</Text>
</Box>
These also support the ‘responsive props’ format which allows you to specify a set of values for different screen sizes.
For example, if you wanted small spacing on mobile but medium spacing from tablet upwards:
Lorem ipsum dolor sit amet.
<Box padding={{ mobile: "small", tablet: "medium" }}>
  <Text>Lorem ipsum dolor sit amet.</Text>
</Box>
If required, you’re also able to specify different values for larger screens.
For example, if you wanted to set the previous example’s spacing to large on desktop and xlarge on wide:
Lorem ipsum dolor sit amet.
<Box
  padding={{
    mobile: "small",
    tablet: "medium",
    desktop: "large",
    wide: "xlarge",
  }}
>
  <Text>Lorem ipsum dolor sit amet.</Text>
</Box>
Rather than nesting content in arbitrary Box elements, you may prefer to use standard Card elements instead.
Lorem ipsum dolor sit amet.
<Card>
  <Text>Lorem ipsum dolor sit amet.</Text>
</Card>
The most common white space on screen is between elements stacked vertically. For this use case, Braid provides a Stack component that accepts a ‘space’ prop.
For example, if you wanted to render a stack of Heading and Text elements with large spacing between them:

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada, massa nec ultricies efficitur, lectus ante consequat magna, a porttitor massa ex ut quam.
Phasellus ipsum tortor, aliquet dapibus fermentum in, mollis vel metus. Vestibulum malesuada ante eu velit malesuada, nec ultricies sapien finibus. Aenean rutrum in sem a ullamcorper. Integer ut euismod urna. Interdum et malesuada fames ac ante ipsum primis in faucibus.
<Card>
  <Stack space="large">
    <Heading level="3">Heading</Heading>
    <Text>{lipsum1}</Text>
    <Text>{lipsum2}</Text>
  </Stack>
</Card>
Just like Box, you can also specify different spacing values for different screen sizes:

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada, massa nec ultricies efficitur, lectus ante consequat magna, a porttitor massa ex ut quam.
Phasellus ipsum tortor, aliquet dapibus fermentum in, mollis vel metus. Vestibulum malesuada ante eu velit malesuada, nec ultricies sapien finibus. Aenean rutrum in sem a ullamcorper. Integer ut euismod urna. Interdum et malesuada fames ac ante ipsum primis in faucibus.
<Card>
  <Stack space={{ mobile: "medium", tablet: "large" }}>
    <Heading level="3">Heading</Heading>
    <Text>{lipsum1}</Text>
    <Text>{lipsum2}</Text>
  </Stack>
</Card>
To visually break up content, you can insert dividers between all stack elements by setting the dividers prop on Stack:

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada, massa nec ultricies efficitur, lectus ante consequat magna, a porttitor massa ex ut quam.
Phasellus ipsum tortor, aliquet dapibus fermentum in, mollis vel metus. Vestibulum malesuada ante eu velit malesuada, nec ultricies sapien finibus. Aenean rutrum in sem a ullamcorper. Integer ut euismod urna. Interdum et malesuada fames ac ante ipsum primis in faucibus.
<Card>
  <Stack space="gutter" dividers={true}>
    <Heading level="3">Heading</Heading>
    <Text>{lipsum1}</Text>
    <Text>{lipsum2}</Text>
  </Stack>
</Card>
If you’d prefer to take control over the placement of dividers, you can use the Divider component directly:

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada, massa nec ultricies efficitur, lectus ante consequat magna, a porttitor massa ex ut quam.
Phasellus ipsum tortor, aliquet dapibus fermentum in, mollis vel metus. Vestibulum malesuada ante eu velit malesuada, nec ultricies sapien finibus. Aenean rutrum in sem a ullamcorper. Integer ut euismod urna. Interdum et malesuada fames ac ante ipsum primis in faucibus.
<Card>
  <Stack space="gutter">
    <Heading level="3">Heading</Heading>
    <Text>{lipsum1}</Text>
    <Divider />
    <Text>{lipsum2}</Text>
  </Stack>
</Card>
Multiple Stack components can be nested to create more complex white space rules. For example, if you wanted to create multiple grouped blocks of text like you might see on a job summary card:

Heading

Line 1
Line 2
Line 3
Line 1
Line 2
Line 3
<Card>
  <Stack space="gutter">
    <Heading level="4">Heading</Heading>
    <Stack space="small">
      <Text>Line 1</Text>
      <Text>Line 2</Text>
      <Text>Line 3</Text>
    </Stack>
    <Stack space="small">
      <Text>Line 1</Text>
      <Text>Line 2</Text>
      <Text>Line 3</Text>
    </Stack>
  </Stack>
</Card>
Stack also supports horizontal alignment. For example, if you wanted to centre align all content within a card:
Badge

Heading Text

Lorem ipsum dolor sit amet.
<Card>
  <Stack space="medium" align="center">
    <IconPromote tone="promote" />
    <Badge tone="promote">Badge</Badge>
    <Heading align="center" level="4">
      Heading Text
    </Heading>
    <Text align="center" tone="secondary">
      Lorem ipsum dolor sit amet.
    </Text>
  </Stack>
</Card>
Individual stack items can be hidden on different screen sizes by wrapping them with the Hidden component. For example, if you wanted to hide the second item in a stack on mobile:
Item 1
Item 2
Item 3
<Card>
  <Stack space="medium" align="center">
    <Text>Item 1</Text>
    <Hidden below="tablet">
      <Text>Item 2</Text>
    </Hidden>
    <Text>Item 3</Text>
  </Stack>
</Card>
If you’d like to render a set of components in a row with equal spacing around them, wrapping onto multiple lines when necessary, Braid provides an Inline component:
Lorem ipsum
Dolor
Sit amet
Consectetur
Adipiscing elit
Suspendisse dignissim
Dapibus elit
Vel egestas felis
Pharetra non
<Card>
  <Inline space="small">
    <Badge>Lorem ipsum</Badge>
    <Badge>Dolor</Badge>
    <Badge>Sit amet</Badge>
    <Badge>Consectetur</Badge>
    <Badge>Adipiscing elit</Badge>
    <Badge>Suspendisse dignissim</Badge>
    <Badge>Dapibus elit</Badge>
    <Badge>Vel egestas felis</Badge>
    <Badge>Pharetra non</Badge>
  </Inline>
</Card>
Similar to Stack, Inline also supports horizontal alignment of its children:
Lorem ipsum
Dolor
Sit amet
<Card>
  <Inline space="small" align="center">
    <Badge>Lorem ipsum</Badge>
    <Badge>Dolor</Badge>
    <Badge>Sit amet</Badge>
  </Inline>
</Card>
If you’d like the columns to stack vertically on smaller screens, you can provide the collapseBelow prop.
For example, if you wanted buttons to be rendered vertically on mobile but horizontally from tablet upwards:
<Card>
  <Inline space="small" collapseBelow="tablet">
    <Button>Submit</Button>
    <Button variant="ghost">Cancel</Button>
  </Inline>
</Card>
If you need to lay out content horizontally, Braid provides the Columns and Column components:
Column 1
Column 2
<Columns space="small">
  <Column>
    <Card>
      <Text>Column 1</Text>
    </Card>
  </Column>
  <Column>
    <Card>
      <Text>Column 2</Text>
    </Card>
  </Column>
</Columns>
Similar to Inline, if you’d like the columns to stack vertically on smaller screens, you can provide the collapseBelow prop.
For example, if you wanted cards to be rendered vertically on mobile but horizontally from tablet upwards:
Column 1
Column 2
<Columns space="small" collapseBelow="tablet">
  <Column>
    <Card>
      <Text>Column 1</Text>
    </Card>
  </Column>
  <Column>
    <Card>
      <Text>Column 2</Text>
    </Card>
  </Column>
</Columns>
All columns are of equal width by default, but you can also customise the width of each column individually.
For example, if you wanted to render a main content area and a sidebar, collapsing to a single column on mobile:
Sidebar
Main content
<Columns space="small" collapseBelow="tablet">
  <Column width="1/3">
    <Card>
      <Text>Sidebar</Text>
    </Card>
  </Column>
  <Column>
    <Card>
      <Text>Main content</Text>
    </Card>
  </Column>
</Columns>
If you want a column to be as small as possible, you can also set its width to content which ensures that it’s only as wide as the content within it.
For example, if you wanted a card with a left-aligned Heading and a right-aligned OverflowMenu:

Card heading

Card content
<Card>
  <Stack space="medium">
    <Columns space="small">
      <Column>
        <Heading level="3">Card heading</Heading>
      </Column>
      <Column width="content">
        <OverflowMenu label="Options">
          <MenuItem
            onClick={() => {
              /* */
            }}
          >
            First
          </MenuItem>
          <MenuItem
            onClick={() => {
              /* */
            }}
          >
            Second
          </MenuItem>
        </OverflowMenu>
      </Column>
    </Columns>
    <Text>Card content</Text>
  </Stack>
</Card>
By default, columns are rendered in document order, which also doubles as the screen reader order. If you need the columns to be visually reversed on larger screens, you can provide the reverse option:
Sidebar
Main content
<Columns space="small" collapseBelow="tablet" reverse>
  <Column width="1/3">
    <Card>
      <Text>Sidebar</Text>
    </Card>
  </Column>
  <Column>
    <Card>
      <Text>Main content</Text>
    </Card>
  </Column>
</Columns>
If you have columns that are of varying height, you can center them vertically with the alignY prop:
Column
Column
Column
Column
Column
Column
Column
Column
<Columns space="small" alignY="center">
  <Column>
    <Card>
      <Stack space="medium" align="center">
        <Text>Column</Text>
        <Text>Column</Text>
      </Stack>
    </Card>
  </Column>
  <Column>
    <Card>
      <Stack space="medium" align="center">
        <Text>Column</Text>
        <Text>Column</Text>
        <Text>Column</Text>
        <Text>Column</Text>
      </Stack>
    </Card>
  </Column>
  <Column>
    <Card>
      <Stack space="medium" align="center">
        <Text>Column</Text>
        <Text>Column</Text>
      </Stack>
    </Card>
  </Column>
</Columns>
If you’d like to render a grid of components with equal spacing between them, Braid provides a Tiles component:
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
<Tiles columns={3} space="small">
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
</Tiles>
If you need to customise the spacing and number of columns per screen size, the columns prop is responsive. For example, if you wanted a single column on mobile and three columns from tablet upwards:
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
<Tiles
  columns={{ mobile: 1, tablet: 3 }}
  space={{ mobile: "xsmall", tablet: "small" }}
>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
</Tiles>
When the tiles are collapsed to a single column, you can optionally show dividers between them with the dividers prop:
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
Tile
<Tiles
  columns={{ mobile: 1, tablet: 3 }}
  space={{ mobile: "none", tablet: "small" }}
  dividers
>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
  <Card>
    <Text>Tile</Text>
  </Card>
</Tiles>
By default, all layout components will render full width. However, most applications will want to limit the width of content on the screen. In order to address this, Braid provides the ContentBlock component that sets a maximum width and centres content horizontally.
Hello World
<ContentBlock>
  <Card>
    <Text>Hello World</Text>
  </Card>
</ContentBlock>
If you’d like a larger content block, you can optionally provide the width prop:
Hello World
<ContentBlock width="large">
  <Card>
    <Text>Hello World</Text>
  </Card>
</ContentBlock>
For top-level sections, in addition to limiting the width of content on the screen, it is also important to standardise the gutter between content and the edge of the screen. For this Braid provides the PageBlock component, which defines responsive gutters around a ContentBlock.
Hello World
<PageBlock>
  <Card>
    <Text>Hello World</Text>
  </Card>
</PageBlock>
To standardise our page-level block widths, the width prop accepts either medium or large.
Hello World
<PageBlock width="large">
  <Card>
    <Text>Hello World</Text>
  </Card>
</PageBlock>
For establishing consistent page-level layout, Braid provides the Page component — responsible for managing the relationship between the footer and the main content. This ensures at a minimum the footer is always positioned at the bottom of the screen, pushed beyond as the page content grows.
Header
Content
Footer
<Page
  footer={
    <Box background="promoteLight">
      <Placeholder label="Footer" height={100} />
    </Box>
  }
>
  <Placeholder label="Header" height={50} />
  <Placeholder label="Content" height={50} />
</Page>
For pages with dynamic content it is recommended to place the footer out of view by setting the footerPosition prop to belowFold. This prevents the footer from popping in and out of view when the page content changes, e.g. toggling between a loading indicator and content.
Header
Content
Footer
<Page
  footer={
    <Box background="promoteLight">
      <Placeholder label="Footer" height={100} />
    </Box>
  }
  footerPosition="belowFold"
>
  <Placeholder label="Header" height={50} />
  <Placeholder label="Content" height={50} />
</Page>
Sometimes it is necessary for a component to extend out into it’s surrounding layout. We can achieve this using the Bleed component.
Consider the following example where we have a Card containing a header image, a Heading and some Text. The Card applies internal spacing, indenting the content from the edges of the container.
Header Image

Heading

Text content
<Card>
  <Stack space="gutter">
    <Placeholder height={200} label="Header Image" />
    <Heading level="3">Heading</Heading>
    <Text>Text content</Text>
  </Stack>
</Card>
If we want the image to run to the edges of the container, we can wrap it in a Bleed and define which direction and how far we want the image to bleed into the surrounding layout.
In this case, let’s bleed horizontally and also out the top:
Header Image

Heading

Text content
<Card>
  <Stack space="gutter">
    <Bleed horizontal="gutter" top="gutter">
      <Placeholder height={200} label="Header Image" />
    </Bleed>
    <Heading level="3">Heading</Heading>
    <Text>Text content</Text>
  </Stack>
</Card>
Given this is achieved using negative margins, it is important to ensure that size and direction of the bleed is accommodated by the parent layout. In this case, ensure we do not choose bleed values that exceed the indent of the parent Card component.