Layout
App shell and sidebar
The signed-in app frame: a fixed sidebar with tree navigation, a main column, and a drawer with a top bar under 768px.
Examples
A sidebar with a folder, a section and the collapsed state
<AppShell>
<SidebarOverlay open={mobileOpen} onClose={close} />
<Sidebar id="app-navigation" aria-label="Primary navigation" open={mobileOpen}>
<SidebarHeader collapsed={collapsed}>
<SidebarBrand component={Link} href="/dashboard" tile={<GitHubIcon size={15} />}>Observatory</SidebarBrand>
<SidebarToggle collapsed={collapsed} onToggle={toggle} />
</SidebarHeader>
<SidebarNav>
<TreeNode component={Link} href="/dashboard" icon={<LayoutDashboard size={18} />} label="Dashboard" active collapsed={collapsed} />
<TreeGroup>
<TreeNode component="button" icon={<BarChart3 size={18} />} label="Analytics" chevron="open" onClick={toggleAnalytics} />
<TreeChildren>
<TreeNode component={Link} href="/analytics/runs" icon={<Terminal size={16} />} label="Run logs" />
</TreeChildren>
</TreeGroup>
<SidebarSection>Agentic assistance</SidebarSection>
<TreeNode component="button" icon={<Plus size={16} />} label="New analysis chat" accent onClick={newChat} />
</SidebarNav>
<SidebarFooter>…</SidebarFooter>
</Sidebar>
<AppContent>
<MobileHeader title="Observatory" onOpenMenu={open} navId="app-navigation" />
<AppMain id="main-content">{children}</AppMain>
</AppContent>
</AppShell>Guidelines
- AppShell wraps SidebarOverlay, Sidebar and AppContent; AppContent holds MobileHeader and AppMain. The sidebar's width is --sidebar-width; <html data-sidebar="collapsed"> narrows it, so set that attribute before first paint from the stored preference.
- A TreeNode is a link (pass component={Link}), a folder toggle (component="button" with chevron) or an action (accent for the one primary action). Collapsed rows show the icon only and the label in a tooltip.
- Product routes first, then a SidebarSection per secondary group; the author's own links last. The footer holds the account and the sign-in or sign-out control.
- Under 768px the Sidebar opens as a drawer over SidebarOverlay; the MobileHeader's button opens it and Escape closes it.
Props
| Prop | Type | What it does |
|---|---|---|
| TreeNode: component, href, icon, label, active, collapsed, tooltip, chevron, trailing, external, disabled, accent | see the types | One row; a button without an href, a link with one. |
| Sidebar: open, id, aria-label | boolean, string, string | The drawer state and the id the MobileHeader points at. |
| MobileHeader: title, onOpenMenu, menuOpen, navId, trailing | ReactNode, () => void, boolean, string, ReactNode | The 56px bar under 768px. |
| SidebarHeader: collapsed · SidebarToggle: collapsed, onToggle · SidebarBrand: component, href, tile | … | The header row. |