- Implementation
- Page Props
- Page.Header Props
- Page.Content Props
- Page.Panel Props
- Page.Panel.Header Props
- Page.Panel.Content Props
Common Examples
Page components
In Anvil2, thePage 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 ofPage.Sidebarto 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 anh1.Page.Content: wraps the primary content of the page, and renders as an HTMLsectionelement. InsidePageit portals into the shell’smainlandmark. OutsidePageit renders in place. Use it with aLayoutcomponent so the content width matchesPage.Header.Page.Panel: an optional section on the right side of the page. The root is adiv. Omitopenfor a persistent panel. Passopento show and hide it. Below 1024px, a controlled panel renders inside a Dialog.Page.Panel.Header,Page.Panel.Content, andPage.Panel.Footer: panel regions on the betaPageimported from@servicetitan/anvil2/beta. The header stays pinned. Content and footer can pin withsticky.Page.Footer: an optional footer inside the page. It renders an HTMLfooter, portals into the shell’s footer slot, and supports layout utility props. OutsidePageit renders in place.
Adding side bars to the page
ThePage.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.Sidebar collapsed state in local storage
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
ThePage.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 anonChange 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
PlacePage.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 betaPage 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.Adding a footer to the page
ThePage.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
ThePage 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 matchesPage.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 withoverflow: auto: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.