AppShell
A CSS Grid container with three named areas sidebar, header, and main.
<AppShell> is a CSS Grid container that divides the viewport into three areas: a sidebar on the left, a header on the top right, and the page below the header. The document itself scrolls. The sidebar sticks to the viewport with position: sticky, and the header stays pinned at the top via <TopNavigation>'s own sticky positioning.
Place <Sidebar>, <TopNavigation>, and <Page> directly as children. Each owns its own grid area, so the order does not matter and there are no wrapper sub-components.
Looking for composition guidance?
This page covers the component API. For a step-by-step guide on where to place content, how to wire up navigation, and responsive strategy, see the App Frame pattern.
Usage
Basic structure
<AppShell defaultSidebarOpen>
<Sidebar>
<Sidebar.Header>{/* Logo */}</Sidebar.Header>
<Sidebar.Nav>{/* Navigation items */}</Sidebar.Nav>
</Sidebar>
<TopNavigation>
<TopNavigation.Start>{/* Toggle */}</TopNavigation.Start>
<TopNavigation.Middle>{/* Breadcrumbs, search */}</TopNavigation.Middle>
<TopNavigation.End>{/* User menu */}</TopNavigation.End>
</TopNavigation>
<Page>
<Page.Header>{/* Title, description, actions */}</Page.Header>
{/* Panels and page content */}
</Page>
</AppShell>import { AppShell, Description, Page, Panel, Sidebar, Text, Title, TopNavigation,} from '@marigold/components';import { DemoViewport } from '@/ui/DemoViewport';export default () => ( <DemoViewport> <AppShell defaultSidebarOpen> <Sidebar> <Sidebar.Header> <span className="text-sm font-medium">Logo</span> </Sidebar.Header> <Sidebar.Nav> <Sidebar.Item href="#">Navigation 1</Sidebar.Item> <Sidebar.Item href="#">Navigation 2</Sidebar.Item> <Sidebar.Item href="#">Navigation 3</Sidebar.Item> </Sidebar.Nav> </Sidebar> <TopNavigation> <TopNavigation.Start> <Sidebar.Toggle /> </TopNavigation.Start> <TopNavigation.Middle> <span className="text-sm">Breadcrumbs</span> </TopNavigation.Middle> <TopNavigation.End> <span className="text-sm">User Menu</span> </TopNavigation.End> </TopNavigation> <Page> <Page.Header> <Title>Dashboard</Title> <Description>An overview of your workspace.</Description> </Page.Header> {Array.from({ length: 3 }, (_, i) => ( <Panel key={i}> <Panel.Header> <Title>Section {i + 1}</Title> </Panel.Header> <Panel.Content> <Text size="sm">Panel content</Text> </Panel.Content> </Panel> ))} </Page> </AppShell> </DemoViewport>);Sidebar state
<AppShell> manages the sidebar's open/collapsed state for you. It wraps its children in a Sidebar.Provider internally. Pass defaultSidebarOpen to start expanded. The sidebar toggle in the header and the sidebar share this state automatically, with no provider boilerplate.
For controlled sidebar state (open / onOpenChange) or to set the sidebar's variant / size, render your own <Sidebar.Provider> around <AppShell>. <AppShell> detects the outer provider and uses it instead of creating its own:
<Sidebar.Provider open={open} onOpenChange={setOpen}>
<AppShell>{/* … */}</AppShell>
</Sidebar.Provider>Scrolling
The page itself scrolls. <AppShell> does not create an interior scroll container. The sidebar and header stick to the viewport via position: sticky, so they stay visible as the user scrolls the page. The sidebar's navigation area scrolls independently when it has too many items to fit, which the Sidebar component handles internally.
Page-level scroll keeps native browser behaviour (mobile URL-bar collapse, pull-to-refresh, scroll restoration on back/forward, Cmd+F find-in-page, and anchor links) working without extra wiring.
Don't
- Don't nest
<AppShell>inside other layout containers - Don't put page content directly in
<AppShell>. Wrap it in a<Page>so it gets themainlandmark, padding, and rhythm - Don't use
<AppShell>for simple pages that only need a header or only a sidebar
Accessibility
- Landmarks:
<Page>renders<main>and<Sidebar>renders<aside>, so both appear in the screen reader's landmark list automatically. Wrap them withuseLandmarkto add them to theF6cycle. See the Landmarks foundation for details. - Stacking order: The header uses
z-index: 1to ensure it stays above the page content during scroll.
Note
<AppShell> is a structural layout component. Accessibility features like keyboard navigation, focus management, and ARIA attributes are provided by the components placed inside it. See Sidebar and TopNavigation for their accessibility details.
Props
AppShell
Prop
Type
Accessibility props (54)
Prop
Type
DOM event handlers (164)
Prop
Type
Related components
Page: The content area inside
<AppShell>, providing themainlandmark, padding, and vertical rhythm.Sidebar: Use standalone when you only need side navigation without a fixed header bar.
TopNavigation: Use standalone for a horizontal navigation bar without a sidebar.
Grid: Use for custom grid layouts that don't follow the L-shape pattern.