Skip to main content

Common Examples

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. Below 1024px it becomes a popover opened from a trigger button.
  • Page.SidebarHeader: used as the first child of Page.Sidebar to format a header using a Text component. The heading is hidden from assistive technology while the sidebar is collapsed.
  • Page.Header: top section of the page where page actions and title go. The title renders as an h1.
  • Page.Content: wraps the primary content of the page, and renders as an HTML section element. Inside Page it portals into the shell’s main landmark. Outside Page it renders in place. Use it with a Layout component so the content width matches Page.Header.
  • Page.Panel: an optional section on the right side of the page. The root is a div. Omit open for a persistent panel. Pass open to show and hide it. Below 1024px, a controlled panel renders inside a Dialog.
  • Page.Panel.Header, Page.Panel.Content, and Page.Panel.Footer: panel regions on the beta Page imported from @servicetitan/anvil2/beta. The header stays pinned. Content and footer can pin with sticky.
  • Page.Footer: an optional footer inside the page. It renders an HTML footer, portals into the shell’s footer slot, and supports layout utility props. Outside Page it renders in place.

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.
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.

Adding the header to the page

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. Both default to a fixed layout with a 1280px max width; omit layout unless the content Layout is fluid or uses a non-default variant.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.

User-editing for the header title text

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.

Adding panels to the page

Place Page.Panel as a child of Page, usually after the sidebar and content.Omit open when the panel is always present. Pass open when the page shows and hides it. Below 1024px, a panel with open set renders inside a dialog instead of beside the content. A panel that omits open stays in the page flow and stacks under the main content at that width.size sets the desktop width: "small" (16rem), "medium" (24rem, the default), or "large" (30rem). Panels pad their inner content. Set noPadding to remove that padding.

Drill-down inside a panel

Page.Panel hosts DrillDown the same way Dialog and Drawer do. The stack starts closed. defaultDrillDownIndex is the screen the first next() opens from that closed stack, and the index restored when the panel closes. It defaults to 0. When a parent needs setIndex, back, or next, spread drillDownProps from useDrillDown() onto the panel.

Panel regions on the beta Page

The beta Page from @servicetitan/anvil2/beta adds Page.Panel.Header, Page.Panel.Content, and Page.Panel.Footer. The header is pinned above the scrolling regions. Set sticky on a content region to pin it under the header, and on the footer to pin it to the bottom of the panel. Footer actions wrap and align to the end.

Scrolling

Page from @servicetitan/anvil2 scrolls with the window. At 1024px and wider, a virtual scrollbar on the content stays in sync with that window scroll.Beta Page from @servicetitan/anvil2/beta uses one scroll region for every Page.Content at 1024px and wider. Those sections portal into a single main landmark, and that landmark scrolls on its own. It is a tab stop: focus it, then use Page Up and Page Down. Below 1024px, the beta page scrolls with the document and the landmark is not a tab stop.The Page.Footer component renders a semantic footer element within the page content area. It can be placed as a child of Page after the content or panel to add supplemental information or secondary actions.

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 components are available to configure dynamic layouts on a page:
  • Layout: define content max-width and column structure (usually the direct descendant 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.

Handling horizontal scrolling

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:
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.

React Accessibility

Page.Header renders the title as an h1. Use one header per page.The desktop sidebar toggle is a button named “Open Sidebar” or “Close Sidebar”. Collapsed sidebar content uses display: none and aria-hidden, so keyboard focus stays on the toggle. Below 1024px the sidebar is a button named with currentPageTitle, or “Menu” when that prop is omitted. Activating it opens a popover, and choosing a link inside the popover closes it.Title editing replaces the heading with a text field. Escape cancels and restores the previous title. Enter confirms the edit unless onChange returns false. The edit, confirm, and cancel controls have accessible names. Override them with editButtonLabel, editFieldLabel, confirmButtonLabel, and cancelButtonLabel.Secondary actions that collapse into the overflow control use a button named “More actions”. A primary action that passes items is a menu trigger. Both follow Menu keyboard behavior.A panel with open={false} sets aria-hidden and aria-disabled. Below 1024px, a controlled panel renders in a dialog and uses that dialog’s focus trap. On large screens, an open controlled panel sets tabIndex={0} on its scroll region so Page Up and Page Down can scroll it. Omitting open keeps the panel visible in the layout, and the panel still sets aria-hidden because that attribute is !open. Persistent panel content is visible and removed from the accessibility tree.On the beta Page, the main landmark is a tab stop at 1024px and wider. Focus it, then use Page Up and Page Down to scroll the content.
Last modified on October 5, 2026