Overview
Having a consistent place for navigation and similar elements is one of the key nature of good UI design. These page layouts show guidelines for element positioning to support different use cases and include examples and details to stay consistent with other pages.
Use Cases
When adding a large data set to a page
When adding a small data set that is primarily visual
Configuration of features
Table Page
A table is one of the most complex objects that can live on a page. It can have infinite combinations of features which makes putting it in a page with consistency challenging. Below are our guidelines to achieve consistency for page with a table.
Default
Commonly used layout for most pages that contains table.
<State initial={0}>
{([active, setActive]) => (
<Frame
style={{ minHeight: 500 }}
header={
<div style={{ height: 56 }}>
<div style={{ backgroundColor: 'black', height: 56, position: 'fixed', top: 0, width: '100%', zIndex: 1 }} />
</div>
}
>
<Page
header={
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Headline size="large" className="m-b-0">Page Header</Headline>
</Stack.Item>
<Button small primary>Create Flow</Button>
</Stack>
}
sidebar={
<Sidebar localStorageKey="page-layout__default">
<SideNav title="Drinks">
<SideNav.Item onClick={() => setActive(0)} active={active===0}>Milk Tea</SideNav.Item>
<SideNav.Item onClick={() => setActive(1)} active={active===1}>Coffee</SideNav.Item>
<SideNav.Item onClick={() => setActive(2)} active={active===2}>Smoothie</SideNav.Item>
</SideNav>
<Sidebar.Section>
<Card onClick={() => setActive(3)} active={active===3}>Hello World</Card>
</Sidebar.Section>
</Sidebar>
}
>
<Layout>
<Table data={[
{ id: 1, name: 'Rose Milk Tea', price: 4.75 },
{ id: 2, name: 'Honey Milk Tea', price: 5.75 },
{ id: 3, name: 'Horchata Milk Tea', price: 5.00 },
{ id: 4, name: 'KitKat Milk Tea', price: 5.75 },
{ id: 6, name: 'Caramel Milk Tea', price: 4.75 },
{ id: 7, name: 'Original Milk Tea', price: 4.75 },
{ id: 8, name: 'Mango Milk Tea', price: 5.00 },
{ id: 9, name: 'Oolong Milk Tea', price: 4.75 }
]}>
<TableColumn field="id" title="Id" width="60px" />
<TableColumn field="name" title="Name" />
<TableColumn field="price" title="Price" width="180px" format="{0:c}" />
</Table>
</Layout>
</Page>
</Frame>
)}
</State>
Wide
Used when table requires additional space on the page.
<State initial={0}>
{([active, setActive]) => (
<Frame
style={{ minHeight: 500 }}
header={
<div style={{height: 56}}>
<div style={{ backgroundColor: 'black', height: 56, position: 'fixed', top: 0, width: '100%', zIndex: 1 }} />
</div>
}
>
<Page
maxWidth='wide'
header={
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Headline size="large" className="m-b-0">Page Header</Headline>
</Stack.Item>
<Button small primary>Create Flow</Button>
</Stack>
}
sidebar={
<Sidebar localStorageKey="page_layout__wide">
<SideNav title="Drinks">
<SideNav.Item onClick={() => setActive(0)} active={active===0}>Milk Tea</SideNav.Item>
<SideNav.Item onClick={() => setActive(1)} active={active===1}>Coffee</SideNav.Item>
<SideNav.Item onClick={() => setActive(2)} active={active===2}>Smoothie</SideNav.Item>
</SideNav>
<Sidebar.Section>
<Card onClick={() => setActive(3)} active={active===3}>Hello World</Card>
</Sidebar.Section>
</Sidebar>
}
>
<Layout>
<Table data={[
{ id: 1, name: 'Rose Milk Tea', price: 4.75 },
{ id: 2, name: 'Honey Milk Tea', price: 5.75 },
{ id: 3, name: 'Horchata Milk Tea', price: 5.00 },
{ id: 4, name: 'KitKat Milk Tea', price: 5.75 },
{ id: 6, name: 'Caramel Milk Tea', price: 4.75 },
{ id: 7, name: 'Original Milk Tea', price: 4.75 },
{ id: 8, name: 'Mango Milk Tea', price: 5.00 },
{ id: 9, name: 'Oolong Milk Tea', price: 4.75 }
]}>
<TableColumn field="id" title="Id" width="60px" />
<TableColumn field="name" title="Name" />
<TableColumn field="price" title="Price" width="180px" format="{0:c}" />
</Table>
</Layout>
</Page>
</Frame>
)}
</State>
Card Page
A card page is used to show a smaller data set that is primarily visual, such as displaying images of an item.
<State initial={0}>
{([active, setActive]) => (
<Frame header={
<div style={{ height: 56 }}>
<div style={{ backgroundColor: 'black', height: 56, position: 'fixed', top: 0, width: '100%', zIndex: 1 }} />
</div>
}
>
<Page
header={
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Headline size="large" className="m-b-0">Page Header</Headline>
</Stack.Item>
<Button small primary>Create Flow</Button>
</Stack>
}
sidebar={
<Sidebar localStorageKey="page-layout__card-page">
<SideNav title="Drinks">
<SideNav.Item onClick={() => setActive(0)} active={active===0}>Milk Tea</SideNav.Item>
<SideNav.Item onClick={() => setActive(1)} active={active===1}>Coffee</SideNav.Item>
<SideNav.Item onClick={() => setActive(2)} active={active===2}>Smoothie</SideNav.Item>
</SideNav>
<Sidebar.Section>
<Card onClick={() => setActive(3)} active={active===3}>Hello World</Card>
</Sidebar.Section>
</Sidebar>
}
>
<Layout type="2Col" spacing="relaxed">
{[
{ id: 1, name: 'Rose Milk Tea', price: 4.75 },
{ id: 2, name: 'Honey Milk Tea', price: 5.75 },
{ id: 3, name: 'Horchata Milk Tea', price: 5.00 },
{ id: 4, name: 'KitKat Milk Tea', price: 5.75 },
{ id: 6, name: 'Caramel Milk Tea', price: 4.75 },
{ id: 7, name: 'Original Milk Tea', price: 4.75 },
{ id: 8, name: 'Mango Milk Tea', price: 5.00 },
{ id: 9, name: 'Oolong Milk Tea', price: 4.75 }
].map(
(item, index) => {
return (
<Layout.Section key={index}>
<Card hoverable>
<Card.Section>
<Icon name="local_drink" /><BodyText inline className="h3 m-l-2 m-b-1">{item.name}</BodyText>
</Card.Section>
<Card.Section light className="c-neutral-90 fs-2">{item.price}</Card.Section>
</Card>
</Layout.Section>
)
}
)}
</Layout>
</Page>
</Frame>
)}
</State>
Settings Page
Default
<State initial={0}>
{([active, setActive]) => (
<Frame header={
<div style={{ height: 56 }}>
<div style={{ backgroundColor: 'black', height: 56, position: 'fixed', top: 0, width: '100%', zIndex: 1 }} />
</div>
}
>
<Page
header={
<Headline size="large">Page Header</Headline>
}
sidebar={
<Sidebar localStorageKey="page-layout__settings-page">
<SideNav title="Settings">
<SideNav.Item onClick={() => setActive(0)} active={active===0}>Settings #1</SideNav.Item>
<SideNav.Item onClick={() => setActive(1)} active={active===1}>Settings #2</SideNav.Item>
<SideNav.Item onClick={() => setActive(2)} active={active===2}>Settings #3</SideNav.Item>
</SideNav>
</Sidebar>
}
>
<Divider spacing={2} />
<Layout
type="support"
direction="left"
>
<Layout.Section>
<Headline size="small">Section Title</Headline>
<BodyText size="small" subdued>Dolor incididunt veniam ex quis esse amet eu duis duis minim incididunt labore laboris ex.</BodyText>
</Layout.Section>
<Layout.Section>
<Card>
<Form>
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
<ButtonGroup direction="row-reverse">
<Button primary >Save</Button>
<Button>Cancel</Button>
</ButtonGroup>
</Form>
</Card>
</Layout.Section>
</Layout>
<Divider spacing={2} />
<Layout
type="support"
direction="left"
>
<Layout.Section>
<Headline size="small">Section Title</Headline>
<BodyText size="small" subdued>Dolor incididunt veniam ex quis esse amet eu duis duis minim incididunt labore laboris ex.</BodyText>
</Layout.Section>
<Layout.Section>
<Card className="m-b-1">
<Stack alignItems='center' spacing={2}>
<div className="bg-blue-grey-100 d-f align-items-center justify-content-center" style={{ borderRadius: '100%', width: 40, height: 40 }}>
<Icon name="business" className="c-blue-grey-600" />
</div>
<Stack.Item fill>
<BodyText bold>Item Title</BodyText>
<BodyText subdued>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</BodyText>
</Stack.Item>
<Button fill="subtle" primary>Edit</Button>
</Stack>
</Card>
<Card className="m-b-1">
<Stack alignItems='center' spacing={2}>
<div className="bg-blue-grey-100 d-f align-items-center justify-content-center" style={{ borderRadius: '100%', width: 40, height: 40 }}>
<Icon name="business" className="c-blue-grey-600" />
</div>
<Stack.Item fill>
<BodyText bold>Item Title</BodyText>
<BodyText subdued>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</BodyText>
</Stack.Item>
<Button fill="subtle" primary>Edit</Button>
</Stack>
</Card>
<Card className="m-b-1">
<Stack alignItems='center' spacing={2}>
<div className="bg-blue-grey-100 d-f align-items-center justify-content-center" style={{ borderRadius: '100%', width: 40, height: 40 }}>
<Icon name="business" className="c-blue-grey-600" />
</div>
<Stack.Item fill>
<BodyText bold>Item Title</BodyText>
<BodyText subdued>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</BodyText>
</Stack.Item>
<Button fill="subtle" primary>Edit</Button>
</Stack>
</Card>
</Layout.Section>
</Layout>
</Page>
</Frame>
)}
</State>
Single Save
Use when bulk saving is required on page level.
<State initial={0}>
{([active, setActive]) => (
<Frame header={
<div style={{ height: 56 }}>
<div style={{ backgroundColor: 'black', height: 56, position: 'fixed', top: 0, width: '100%', zIndex: 1 }} />
</div>
}
>
<Page
header={
<Headline size="large">Page Header</Headline>
}
sidebar={
<Sidebar>
<SideNav title="Settings">
<SideNav.Item onClick={() => setActive(0)} active={active===0}>Settings #1</SideNav.Item>
<SideNav.Item onClick={() => setActive(1)} active={active===1}>Settings #2</SideNav.Item>
<SideNav.Item onClick={() => setActive(2)} active={active===2}>Settings #3</SideNav.Item>
</SideNav>
</Sidebar>
}
footer={
<Stack
className="w-100"
justifyContent="space-between"
direction="row-reverse"
>
<ButtonGroup className="flex-row-reverse">
<Button primary>Save</Button>
<Button>Reset</Button>
</ButtonGroup>
</Stack>
}
>
<Divider spacing={2} />
<Layout
type="support"
direction="left"
>
<Layout.Section>
<Headline size="small">Section Title</Headline>
<BodyText size="small" subdued>Dolor incididunt veniam ex quis esse amet eu duis duis minim incididunt labore laboris ex.</BodyText>
</Layout.Section>
<Layout.Section>
<Card>
<Form>
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
</Form>
</Card>
</Layout.Section>
</Layout>
<Divider spacing={2} />
<Layout
type="support"
direction="left"
>
<Layout.Section>
<Headline size="small">Section Title</Headline>
<BodyText size="small" subdued>Dolor incididunt veniam ex quis esse amet eu duis duis minim incididunt labore laboris ex.</BodyText>
</Layout.Section>
<Layout.Section>
<Card>
<Form>
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
</Form>
</Card>
</Layout.Section>
</Layout>
<Divider spacing={2} />
<Layout
type="support"
direction="left"
>
<Layout.Section>
<Headline size="small">Section Title</Headline>
<BodyText size="small" subdued>Dolor incididunt veniam ex quis esse amet eu duis duis minim incididunt labore laboris ex.</BodyText>
</Layout.Section>
<Layout.Section>
<Card>
<Form>
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
<Form.Group widths="equal">
<Form.Input label="Form Label" placeholder="Placeholder" />
<Form.Input label="Form Label" placeholder="Placeholder" />
</Form.Group>
</Form>
</Card>
</Layout.Section>
</Layout>
</Page>
</Frame>
)}
</State>
Anatomy of a Page
The screen of a page is built through several Anvil composition components. Components marked as deprecated, such as the Grid and Container, are not typically apart of building a page.
Frame
The Frame provides the technical structure to the application. It holds the various sub-components of a particular page.
Page
The Page is the outer wrapper for a screen. It provides the background color and width of the page's main content.
The Sidebar is an optional configuration on the left side of the Page. Content inside it is usually through the Side Nav.
Layout
The Layout provides the building blocks of individual pages. Layouts control basic column configurations of content.
Best Practices
- Table placement should be towards the bottom of the viewport if possible.
- Be consistent with sibling page content widths and additional elements on the page.
- Use the same layout width on the entire page page for better alignment and consistency.
- If secondary navigation is required, consider using tabs.