Layout

Organize components in your view

Layout basics

Views use the Stack component to organize items on the page.
The simplest layout uses Stack without any props. This will lay out items vertically some with spacing in between each item.
tsx
Copied
1
<Stack>
2
<Card>Content</Card>
3
<Card>Content</Card>
4
<Card>Content</Card>
5
</Stack>
You can also lay out items horizontally by using the direction prop.
tsx
Copied
1
<Stack direction="row">
2
<Card>Content</Card>
3
<Card>Content</Card>
4
<Card>Content</Card>
5
</Stack>

Nesting layouts

You can achieve more complex layouts by nesting stacks.
In the following example, multiple Stack components are nested inside each other to create a search bar, action group, and list of content.
tsx
Copied
1
<Stack spacing="lg">
2
<Stack direction="row" justify="space-between">
3
<Stack direction="row" justify="end">
4
<TextInput placeholder="Enter a search term" />
5
<Button>Search</Button>
6
</Stack>
7
<Stack direction="row">
8
<Button preset="tertiary">Action 1</Button>
9
<Button preset="tertiary">Action 2</Button>
10
</Stack>
11
</Stack>
12
<Stack>
13
<Card>
14
<Stack direction="row" justify="space-between">
15
<Label>Content</Label>
16
<Stack direction="row">
17
<PencilIcon />
18
<TrashIcon />
19
</Stack>
20
</Stack>
21
</Card>
22
<Card>
23
<Stack direction="row" justify="space-between">
24
<Label>Content</Label>
25
<Stack direction="row">
26
<PencilIcon />
27
<TrashIcon />
28
</Stack>
29
</Stack>
30
</Card>
31
</Stack>
32
</Stack>

Main detail

In the following example, the main content of the page is a table. The detail section has details about the cat.
When a row is selected, the detail section pops up with the details about the cat and shrinks to about 2/3 of the width. The detail section takes up 40u (see Sizing) and grows to fill the remaining space. If the screen gets too small, the detail section will get wrapped to the next row.
tsx
Copied
1
<Stack direction="row" wrap>
2
<Table
3
id={catsTable.id}
4
title="Cats"
5
rowSelection="single"
6
defaultPageSize={3}
7
task="list_cats"
8
grow
9
width={catsTable.selectedRow ? "2/3" : "full"}
10
/>
11
{catsTable.selectedRow && (
12
<Card width="40u" grow>
13
<Title order={3}>{catsTable.selectedRow.name}</Title>
14
<Text>{`My name is ${catsTable.selectedRow.name}`}</Text>
15
<Text>{`I am a ${catsTable.selectedRow.breed}`}</Text>
16
</Card>
17
)}
18
</Stack>

Grid

You can emulate a grid layout by using a row Stack for each row.
In the following example, we have a 2x2 grid of tables. Each table fills up the entire row. If a row gets small enough where both tables can no longer fit, a table will wrap to the next row. You can test this out by resizing your browser.
tsx
Copied
1
<Stack>
2
<Stack direction="row" wrap>
3
<Table showFilter={false} defaultPageSize={3} task="list_dogs" width="72u" grow />
4
<Table showFilter={false} defaultPageSize={3} task="list_dogs" width="72u" grow />
5
</Stack>
6
<Stack direction="row" wrap>
7
<Table showFilter={false} defaultPageSize={3} task="list_cats" width="72u" grow />
8
<Table showFilter={false} defaultPageSize={3} task="list_cats" width="72u" grow />
9
</Stack>
10
</Stack>

Dashboard

You can combine these concepts to lay out a fairly complex and responsive dashboard.
tsx
Copied
1
<Stack>
2
<Stack direction="row" justify="space-between">
3
<Title>Dashboard</Title>
4
<Stack direction="row">
5
<TextInput placeholder="Enter a search term" />
6
<Button>Search</Button>
7
</Stack>
8
</Stack>
9
<Stack direction="row" wrap>
10
<Table title="Cats" defaultPageSize={3} task="list_cats" width="1/2" grow />
11
<Card grow>Content</Card>
12
<Card grow>Content</Card>
13
</Stack>
14
<Stack direction="row" wrap>
15
<Card grow>Content</Card>
16
<Card grow>Longer content</Card>
17
<Card grow>This content takes up a lot of space</Card>
18
</Stack>
19
<Table title="Dogs" defaultPageSize={3} task="list_dogs" />
20
</Stack>

Sizing

Most of our components have the width and height sizing props, which controls how much space the component takes up. width and height take in tokens that represent the size.

Relative sizing

These are tokens that represent a fraction of the available space.
TokenValue
1/250%
1/3, 2/333.333333%, 66.666667%
1/4, 2/4, 3/425%, 50%, 75%
1/5, 2/5, 3/5, 4/520%, 40%, 60%, 80%
1/6, 2/6, 3/6, 4/6, 5/616.666667%, 33.333333%, 50%, 66.666667%, 83.333333%
1/12, 2/12, 3/12, 4/12, 5/12, 6/12, 7/12, 8/12, 9/12, 10/12, 11/128.333333%, 16.666667%, 25%, 33.333333%, 41.666667%, 50%, 58.333333%, 66.666667%, 75%, 83.333333%, 91.666667%
full100%

Absolute sizing

These are tokens that represent an absolute size. We use a 4px sizing unit that we represent using u, for unit. For example, a width of 4u is 16px.
We use a 4px scale to help to better align components in your View without having to tweak raw pixel values.
TokenValue
0.5u0.125rem (2px)
1u0.25rem (4px)
1.5u0.375rem (6px)
2u0.5rem (8px)
2.5u0.625rem (10px)
3u0.75rem (12px)
3.5u0.875rem (14px)
4u1rem (16px)
5u1.25rem (20px)
6u1.5rem (24px)
7u1.75rem (28px)
8u2rem (32px)
9u2.25rem (36px)
10u2.5rem (40px)
11u2.75rem (44px)
12u3rem (48px)
14u3.5rem (56px)
16u4rem (64px)
20u5rem (80px)
24u6rem (96px)
28u7rem (112px)
32u8rem (128px)
36u9rem (144px)
40u10rem (160px)
44u11rem (176px)
48u12rem (192px)
52u13rem (208px)
56u14rem (224px)
60u15rem (240px)
64u16rem (256px)
72u18rem (288px)
80u20rem (320px)
96u24rem (384px)
128u32rem (512px)
192u48rem (768px)
256u64rem (1020px)
We discourage working with raw pixel values. However, you can pass a px value into width or height, e.g. width="100px".