AppShell
Sticky-header + full-height side-nav + single-scroll-container layout with an animated, accessible nav toggle.
Category: layout · WCAG 2.2-AA · shell, layout, sidebar, navigation, drawer, responsive, sticky
States
- open
- closed
Props
| Prop | Type | Default | Description |
|---|---|---|---|
header | ReactNode | — | Top bar (typically a ShellHeader). If a React element, its onMenuClick/menuExpanded are bound to the nav toggle. |
nav | ReactNode | — | Side navigation (typically a SideNav). Fills full height and scrolls internally. |
children | ReactNode | — | Main content, rendered inside the single scroll container. |
footer | ReactNode | — | Optional footer pinned below the content area. |
open | boolean | — | Controlled nav open/visible state. Omit for uncontrolled. |
defaultOpen | boolean | — | Initial open state when uncontrolled. Defaults open on desktop, closed on small screens. |
onOpenChange | (open: boolean) => void | — | Fired when the nav requests open/close (burger, Escape, scrim). |
Design tokens
--cascivo-shell-aside-inline-size--cascivo-shell-panel-inline-size--cascivo-motion-emphasis--cascivo-z-raised--cascivo-z-overlay--cascivo-color-foreground--cascivo-color-background
When to use
- Building an application screen with a persistent header and side navigation
- You want the header burger to toggle the side nav with an animated, accessible show/hide out of the box
- You need one scroll container (the main area) with a fixed header and full-height nav
When not to use
- Marketing/document pages where the whole page should scroll — use a plain Header instead
- A single, always-visible sidebar with no toggle — compose SideNav directly
- You need a persisted collapsible sidebar, a top progress bar, or a right aside — that is the richer copy-paste `layout/app-shell` (different props: `sideNav`/`aside`/`persistKey`/`state`), not this drop-in.
How to build an accessible AppShell in React →
Examples
Header + SideNav + content
The burger in ShellHeader toggles the SideNav automatically.
<AppShell
header={<ShellHeader brand={{ name: 'Acme' }} />}
nav={<SideNav items={items} />}
>
<h1>Dashboard</h1>
</AppShell>Controlled open
<AppShell header={header} nav={nav} open={open.value} onOpenChange={(v) => (open.value = v)}>
…
</AppShell>Related components
- layout/app-shell — A richer, copy-paste-only app shell with a persisted collapsible sidebar, a signal-driven top progress bar, an error strip, and a right aside. Same `AppShell` name, different prop surface (`sideNav`/`aside`/`persistKey`/`state`). Choose this npm drop-in for a simple header + toggleable nav; choose layout/app-shell when you need persistence/progress/aside.
- ShellHeader — Provides the top bar and burger AppShell binds to the nav
- SideNav — The side navigation AppShell lays out full-height