Skip to content
Protocore Design Systemv1.6.9

/// Layout

AppShell

The application frame — an optional env strip and top bar over a sidebar + main body row, with an optional footer and a responsive mobile drawer.

import { AppShell } from "@protocore/pds";
View as Markdown

Basics

Fill the slots — env, topBar, sidebar, footer, and children for the main region. AppShell lays them out as a grid: env strip and top bar pinned on top, sidebar as a fixed column beside the main content, footer below.

STAGING

Dashboard

AppShell wires the env strip, top bar, sidebar, main region, and footer into one frame. On desktop the sidebar is a grid column; below 860px it collapses to a drawer.

Mobile drawer

Below the 860px brand breakpoint the sidebar becomes an off-canvas drawer. Control it with sidebarOpen / onSidebarOpenChange and wire a menu button in the top bar to toggle it; the click-away backdrop closes it.

Controlled drawer

The menu button toggles `sidebarOpen`; the backdrop closes it via `onSidebarOpenChange`. Below 860px the sidebar is an off-canvas drawer.

When to use it

AppShell is the outermost frame for an application — a console or dashboard with persistent chrome. It owns the hard parts: the sticky env/top-bar stack, the sidebar-plus-main grid, and the responsive collapse to a drawer. Use it once, at the root of an app; compose the slots from the layout primitives (TopBar, Sidebar, Footer, EnvStrip — pass env and it renders the strip for you). It is not for marketing pages, which want a plain TopBar + Sections + Footer and no fixed rail. Keep sidebar open-state controlled at the app root so a menu button in the top bar and the backdrop stay in sync.

Usage

Do

  • Use one AppShell at the root of an application to own its chrome.
  • Pass env so the strip renders above the top bar automatically.
  • Control sidebarOpen at the root and wire a top-bar menu button to it.

Don't

  • Wrap marketing pages in AppShell — they want a plain TopBar and Sections.
  • Nest AppShells or hand-build the sidebar/main grid yourself.
  • Leave the mobile drawer uncontrolled if a top-bar button must also toggle it.

Accessibility

KeysAction
TabMove through the top bar, sidebar, main, and footer in DOM order
Enter / SpaceActivate the focused control (e.g. the menu toggle)
EscNot handled by AppShell — wire it to onSidebarOpenChange(false) if you want Esc to close the drawer
  • The frame renders semantic landmarks: `<main>` for content and `<aside>` for the sidebar column.
  • The mobile backdrop is `aria-hidden` and closes the drawer on click.
  • Give a top-bar menu toggle an `aria-label` and reflect the drawer state with `aria-expanded` on your button.

AppShell props

PropTypeDefaultDescription
childrenReactNodeMain content region.
classNamestring
defaultSidebarOpenbooleanfalseUncontrolled initial mobile sidebar open state. Default false.
envenumWhen set, renders a sticky environment strip above the top bar.
envLabelReactNodeOverride the environment strip label.
envMessageReactNodeWayfinding message for the environment strip (grows it into its loud form).
footerReactNodeThe footer slot (e.g. a `<Footer>`), below the body.
onSidebarOpenChange((open: boolean) => void)Fires with the next open state when the mobile sidebar is toggled (e.g. by the click-away backdrop).
sidebarReactNodeThe sidebar slot (e.g. a `<Sidebar>`). A fixed column on desktop; an off-canvas drawer on mobile.
sidebarOpenbooleanControlled mobile sidebar open state. Pair with `onSidebarOpenChange`.
styleCSSProperties
topBarReactNodeThe top bar slot (e.g. a `<TopBar>`), pinned above the body.

Related

  • TopBarA sticky, blurred top navigation bar with brand, mono uppercase links, and an actions cluster.
  • SidebarA left navigation rail of grouped items — mono uppercase group labels over sans links, with an accent rule on the active item.
  • FooterThe shared multi-column site footer — mono uppercase headings over link stacks, an optional accent-count hiring column, and a legal row.
  • EnvStripThe persistent environment band — a sticky full-width dev/staging/prod chrome that colours itself from the env token layer.