Page
The Page is an outer wrapper for the main content of a page. It includes the location for the page title and optionally a Sidebar.
By default, pages have a max width of 1280px
. This can be shrunk to 768px
, or removed altogether.
<div><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Thin Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}maxWidth="narrow"><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Default Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">No Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}maxWidth="wide"><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page></div>
By default, pages do not have a min width. A min width can be enabled on the Page's content to prevent the underlying components from being responsive, creating a horizontal scroll effect. The minimum width value is set to 1280px
for default and wide Pages, and 768px
for narrow Pages. This can be useful when page content is not useful to scale down, such as tables.
<div><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Thin Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}maxWidth="narrow"minWidth><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Default Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}minWidth><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">No Max Width, Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}maxWidth="wide"minWidth><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page></div>
The spacing between the Page content and the rest of the UI can be removed. This is useful when designing for page background stylings (colors, separators).
<div><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Relaxed Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page><br/><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">No Spacing Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}spacing="none"><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page></div>
The content area of a page can also be left aligned.
<div><Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}align="left"><Card><Card.Section red>Content that is apart of the page.</Card.Section></Card></Page></div>
The background color for the page can be set either to neutral-10 (#FCFCFC
, the default) or White/neutral-0 (#FFFFFF
).
<Pageheader={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title on a White Background</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}backgroundColor="neutral-0">Content of the page.</Page>
The page header is where the top content of a page is contained. It currently accepts most forms of content. For more indepth use cases, see the Page Header pattern.
The page footer is where the save and cancel action is contained for page level submission.
<State>{([open, setOpen]) => (<Pagestyle={{ height: '100%' }}header={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item></Stack>}footer={<StackclassName="w-100"justifyContent="space-between"direction="row-reverse"><ButtonGroup className="flex-row-reverse"><ButtonGroup attached><Button primary>Save</Button><Popovertrigger={<ButtonprimaryiconName={`expand_${open ? `less` : `more`}`}onClick={() => setOpen(!open)}/>}onClickOutside={() => setOpen(false)}width="xs"padding={null}open={open}direction="tl"><OptionListoptions={[{ value: 1, text: 'Save as...' }]}/></Popover></ButtonGroup><Button>Reset</Button></ButtonGroup></Stack>}>Content of the page.</Page>)}</State>
The page can include a Sidebar on the left side with consistent sizing. See the Sidebar docs for more information on using Sidebars.
<State initial={0}>{([active, setActive]) => (<Pagesidebar={<Sidebar localStorageKey="page__sidebar"><Sidebar.Section><SideNav title="Marketing"><SideNav.Item onClick={() => setActive(0)} active={active===0}>Dashboard</SideNav.Item><SideNav.Item onClick={() => setActive(1)} active={active===1}>Campaigns</SideNav.Item><SideNav.Item onClick={() => setActive(2)} active={active===2}>Emails</SideNav.Item><SideNav.Item onClick={() => setActive(3)} active={active===3}>Audiences</SideNav.Item></SideNav></Sidebar.Section><Sidebar.Section><Card onClick={() => setActive(4)} active={active===4}>Test</Card></Sidebar.Section></Sidebar>}><Layout type="2Col"><Layout.Section><Card>Card 1</Card></Layout.Section><Layout.Section><Card>Card 2</Card></Layout.Section></Layout></Page>)}</State>
Placed above the page header and content, the Action Toolbar provides a location for the Actions and Inputs components to filter, change, or update content and to take action on selected items.
<State initial={0}>{([active, setActive]) => (<PageactionToolbar={{content: (<Stack style={{ flex: 1 }} justifyContent="space-between"><Stack.Item><ButtonTogglesmalloptions={[{text: "Daily",selected: true,},{text: "Weekly",},{text: "Routing",},]}/></Stack.Item><Stack.Item><Stack><Tooltip text="Schedules"><Button fill="subtle" iconName="watch_later" small /></Tooltip><Divider vertical spacing={2} /><ButtonGroup><Tooltip text="Notifications"><Button fill="subtle" iconName="notifications" small /></Tooltip><Tooltip text="Refresh"><Button fill="subtle" iconName="autorenew" small /></Tooltip><Tooltip text="Settings"><Button fill="subtle" iconName="settings" small /></Tooltip><Tooltip text="Messages"><Button fill="subtle" iconName="email" small /></Tooltip></ButtonGroup></Stack></Stack.Item></Stack>)}}sidebar={<Sidebar><Sidebar.Section><SideNav title="Marketing"><SideNav.Item onClick={() => setActive(0)} active={active===0}>Dashboard</SideNav.Item><SideNav.Item onClick={() => setActive(1)} active={active===1}>Campaigns</SideNav.Item><SideNav.Item onClick={() => setActive(2)} active={active===2}>Emails</SideNav.Item><SideNav.Item onClick={() => setActive(3)} active={active===3}>Audiences</SideNav.Item></SideNav></Sidebar.Section><Sidebar.Section><Card onClick={() => setActive(4)} active={active===4}>Test</Card></Sidebar.Section></Sidebar>}><Layout type="2Col"><Layout.Section><Card>Card 1</Card></Layout.Section><Layout.Section><Card>Card 2</Card></Layout.Section></Layout></Page>)}</State>
Do not use this with Save
action. We have established that pattern for saving content or form to be on the footer of the page.
To preserve visual hierarchy and to minimize vertical space used, use smaller size components, like Small Buttons, 24px Icons, Medium BodyText
Use a sticky positioning when the page length is longer than 2 viewport height, requiring users to scroll multiple times to view the content they need.
<State initial={0}>{([active, setActive]) => (<Pagestyle={{ height: '100%' }}actionToolbar={{sticky: true,content: (<Stack style={{ flex: 1 }} justifyContent="space-between"><Stack.Item><ButtonTogglesmalloptions={[{text: "Daily",selected: true,},{text: "Weekly",},{text: "Routing",},]}/></Stack.Item><Stack.Item><Stack><Tooltip text="Schedules"><Button fill="subtle" iconName="watch_later" small /></Tooltip><Divider vertical spacing={2} /><ButtonGroup><Tooltip text="Notifications"><Button fill="subtle" iconName="notifications" small /></Tooltip><Tooltip text="Refresh"><Button fill="subtle" iconName="autorenew" small /></Tooltip><Tooltip text="Settings"><Button fill="subtle" iconName="settings" small /></Tooltip><Tooltip text="Messages"><Button fill="subtle" iconName="email" small /></Tooltip></ButtonGroup></Stack></Stack.Item></Stack>)}}sidebar={<Sidebar><Sidebar.Section><SideNav title="Marketing"><SideNav.Item onClick={() => setActive(0)} active={active===0}>Dashboard</SideNav.Item><SideNav.Item onClick={() => setActive(1)} active={active===1}>Campaigns</SideNav.Item><SideNav.Item onClick={() => setActive(2)} active={active===2}>Emails</SideNav.Item><SideNav.Item onClick={() => setActive(3)} active={active===3}>Audiences</SideNav.Item></SideNav></Sidebar.Section><Sidebar.Section><Card onClick={() => setActive(4)} active={active===4}>Test</Card></Sidebar.Section></Sidebar>}><Layout type="3Col">{[...Array.from(Array(30).keys())].map((e, i) => (<Layout.Section key={e}><Card><Card.Section style={{ height: 100 }}>Card {i}</Card.Section></Card></Layout.Section>))}</Layout></Page>)}</State>
When horizontal space is limited and the content of the Action Toolbar is overflowing, create a responsive design utilizing components such as an Action Menu to avoid horizontal scrolling and do not wrap it to next line.
This example does not include responsiveness.
<State initial={true}>{([open, setOpen]) => (<PageactionToolbar={{sticky: true,content: (<Stack style={{ flex: 1 }} justifyContent="space-between"><Stack.Item><ButtonTogglesmalloptions={[{text: "Daily",selected: true,},{text: "Weekly",},{text: "Routing",},]}/></Stack.Item><Stack.Item><Stack><Tooltip text="Schedules"><Button fill="subtle" iconName="watch_later" small /></Tooltip><Divider vertical spacing={2} /><Button fill="subtle" iconName="notifications" small /><ActionMenudirection="bl"width="xs"trigger={<Buttonfill="subtle"iconName="more_vert"smallonClick={() => setOpen(!open)}/>}open={open}><ActionMenu.Item>Refresh</ActionMenu.Item><ActionMenu.Item>Settings</ActionMenu.Item><ActionMenu.Item>Messages</ActionMenu.Item></ActionMenu></Stack></Stack.Item></Stack>)}}/>)}</State>
The Panel on a Page displays supplementary content of the Page or select item in the Page.
<Pagestyle={{ height: '100vh' }}panel={{content: (<div><Stack alignItems="center" justifyContent="space-between"><Headline size="small" className="m-0">Page Info</Headline></Stack><BodyText>Supplementary content of the Page here...</BodyText></div>)}}header={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Layout type="2Col"><Layout.Section><Card>Card 1</Card></Layout.Section><Layout.Section><Card>Card 2</Card></Layout.Section></Layout></Page>
<Pagestyle={{ height: '100vh' }}panel={{position: 'left',content: (<div><Stack alignItems="center" justifyContent="space-between"><Headline size="small" className="m-0">Page Info</Headline></Stack><BodyText>Supplementary content of the Page here...</BodyText></div>)}}header={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Layout type="2Col"><Layout.Section><Card>Card 1</Card></Layout.Section><Layout.Section><Card>Card 2</Card></Layout.Section></Layout></Page>
A Panel also has ability to hide and reveal itself. This is used to bring up supplementary content of a selected item on a page.
<State initial={0}>{([open, setOpen]) => (<Pagestyle={{ height: '100vh' }}panel={{open: open,content: (<div><Stack alignItems="center" justifyContent="space-between"><Headline size="small" className="m-0">Card Detail</Headline><Button size="small" fill="subtle" iconName="close" onClick={() => setOpen(false)} /></Stack><BodyText>Supplementary content of the Card here...</BodyText></div>)}}header={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Layout><Layout.Section><Stack spacing={1} direction="column"><Card><Stack alignItems="center" justifyContent="space-between">Card 1<Button onClick={() => setOpen(true)}>show detail</Button></Stack></Card><Card><Stack alignItems="center" justifyContent="space-between">Card 2<Button onClick={() => setOpen(true)}>show detail</Button></Stack></Card></Stack></Layout.Section></Layout></Page>)}</State>
<Pagestyle={{ height: '100vh' }}panel={{noPadding: true,content: (<div><Stack alignItems="center" justifyContent="space-between"><Headline size="small" className="m-0">Page Info</Headline></Stack><BodyText>Supplementary content of the Page here...</BodyText></div>)}}header={<Stack alignItems="center" spacing="0"><Stack.Item fill><Headline size="large">Page Title</Headline><BodyText subdued>A short page description.</BodyText></Stack.Item><Button primary>Action</Button></Stack>}><Layout type="2Col"><Layout.Section><Card>Card 1</Card></Layout.Section><Layout.Section><Card>Card 2</Card></Layout.Section></Layout></Page>
import { Page } from '@servicetitan/design-system';