Implementation
Page Props
Page.Content Props
Page.Panel Props
Common Examples
import { Page, SideNav, Text } from "@servicetitan/anvil2";
const ExampleComponent = () => (
<Page>
<Page.Sidebar>
<Page.SidebarHeader>
<Text variant="headline" el="h2">
Sidebar Header
</Text>
</Page.SidebarHeader>
<SideNav>
<SideNav.Link id="01" href="#">
Nav Link
</SideNav.Link>
</SideNav>
</Page.Sidebar>
<Page.Header title="Page Title" />
<Page.Content>
<Text>Page content.</Text>
</Page.Content>
</Page>
);
Page components
In Anvil2, the Page component is used to create full-page layouts, along with a few sub-components listed below. When implementing Page, ensure you are using the method defined by ST Platform.
Page: the parent component to configure full-page layouts.
Page.Sidebar: a collapsible section on the left side of the page.
Page.SidebarHeader: used as the first child of Page.Sidebar to format a header using a Text component.
Page.Header: top section of the page where page actions and title go.
Page.Content: wraps the primary content of the page, and renders as an HTML main element. It should be used with a Layout component to ensure a consistent and structured design with Page.Header.
Page.Panel: an optional section that takes up the right side of the page and can be expanded or collapsed programmatically. Panels render as HTML aside elements.
Adding side bars to the page
The Page.Sidebar component is usually the first child of a Page, and adds a collapsible section to the left of the rest of the page content.The Page.Sidebar should generally have a Page.SidebarHeader and SideNav as its children to create a consistent, responsive, and user-friendly in-page navigation experience.The sidebar can be omitted if the current page does not require a secondary navigation.<Page>
<Page.Sidebar>
<Page.SidebarHeader>
<Text variant="headline" el="h2">
Sidebar Header
</Text>
</Page.SidebarHeader>
<SideNav>{/* ... side nav links */}</SideNav>
</Page.Sidebar>
<Page.Content>{/* ... page content */}</Page.Content>
</Page>
In order to maintain the collapsed state of the page sidebar after refreshing or navigating to another page, a local storage value is saved to the "sidebar-collapsed" key. The key name can be overridden using the localStorageKey prop.The Page.Header component should go right above the Page.Content section to ensure proper placement. It houses the page title, breadcrumb navigation, page classifications via chips, page actions, page description, and the page preference/setting action trigger.The Page.header is responsive in nature and has the Layout component built into it. It accepts the same properties you would set on your Page.Content layout via its own layout property, and it is recommended that you keep these values in sync to ensure constraints for the sections remain the same.The title in the Page.Header will always be an h1 to adhere to SEO and accessibility best practices.While the page description is a ReactNode, it is recommended to keep the descriptions simple by using Text and Link components. If a page action needs to be made for the page, use the actions property and not the description area.<Page>
<Page.Sidebar>{/* ... sidebar content */}</Page.Sidebar>
<Page.Header
title="Title"
breadcrumbs={breadcrumbs}
chips={chips}
actions={actions}
preferenceAction={{
"aria-label": "Open settings",
onClick: () => {},
}}
description={
<Text>
This page demonstrates all header elements with
<Text inline>
<Link href="#" appearance="primary">
standard actions
</Link>
</Text>
</Text>
}
/>
<Page.Content>{/* ... page content */}</Page.Content>
</Page>
To enable editing the page title, assign an object with an onChange handler to the title prop. This handler will be passed the updated title as a string, which can be used to manage the state for the title.For accessibility, it is recommended to announce that the editing of the page title was successful, which can be accomplished by using a toast.<Page>
<Page.Header
title={{
text: title,
onChange: (newTitle) => {
setTitle(newTitle);
toast.success({ title: "Page title edited" });
}
}}
/>
</Page>
Adding panels to the page
The Page.Panel component can be used as a child of a Page, usually after the sidebar and content.Use the open prop to determine if the panel is displayed, and the size prop to change the width of the panel.By default, panels have padding around the inner content. To disable this, use the noPadding prop.<Page>
<Page.Sidebar>{/* ... sidebar content */}</Page.Sidebar>
<Page.Content>{/* ... page content */}</Page.Content>
<Page.Panel open size="large">
{/* ... panel content */}
</Page.Panel>
</Page>
Best Practices
Use with Layout, Grid, and Flex components
The Page component is the first step in creating consistent and responsive page layouts using Anvil2. Three other component are available to configure dynamic layouts on a page:
- Layout: define content max-width and column structure (usually the direct descendent of
Page.Content) that matches Page.Header.
- Grid: easily use CSS Grid to create dynamic content areas.
- Flex: create CSS Flexbox containers for simple to moderate content layout.
The Page component does not allow horizontal scrolling at the page level by default. This prevents usability and accessibility issues, as users expect vertical scrolling and horizontal scrolling disrupts this mental model.Migrating legacy pages
When migrating legacy pages that aren’t responsive to the A2 Page layout, the recommended approach is to make the page responsive so it works well on all screen sizes. However, if making the page fully responsive is not possible, you can add horizontal scroll handling at the component level for wide content. Wrap specific components that need more horizontal space in a container with overflow: auto:<div style={{ overflowX: "auto" }}>
{/* Wide content that needs horizontal scrolling */}
</div>
This approach ensures that page headers, body text, and navigation remain accessible without horizontal scrolling, while allowing specific components to scroll independently when needed. Some components like Data Table have horizontal scrolling built in.<Page>
<Page.Sidebar>...</Page.Sidebar>
<Page.Header title="Page Title" />
<Page.Content>...</Page.Content>
</Page>
Page Props
The Page component can accept any valid HTML div props.<Page.Content>
<Layout>
<Layout.Item span={12}>Content</Layout.Item>
</Layout>
</Page.Content>
Page.Content Props
The Page.Content component can accept any valid HTML main props.<Page.Panel open={true} size="medium" noPadding={false}>
Panel content
</Page.Panel>
Page.Panel Props
The Page.Panel component can accept any valid HTML aside props, as well as the following:size
"small" | "medium" | "large"
default:"medium"
Last modified on February 12, 2026