Skip to content

Application

App shell

The application frame: a sidebar column, a sticky topbar, a scrolling main region and an optional status strip. It owns the landmarks, the skip link, the responsive switch to off-canvas navigation and the scroll model.

import { AppShell, AppShellContent, AppShellStatusBar, AppShellTopbar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarItem, SidebarMenu, SidebarToggle, } from "@luc/ui/app-shell";

Two states, one component

Expanded is the default. The rail keeps the icons, keeps the labels as the accessible name, and reveals them with the existing tooltip. Ctrl/⌘ + B toggles it; the state persists locally, never in the URL.

Expanded

Skip to content
Overview

Main content scrolls the page. The sidebar scrolls itself, and the topbar never moves.

Prepared locallyUpdated 12:04 UTC

Collapsed rail

Skip to content
Overview

Hover an icon for its label. A parent item with children expands the rail before it opens the tree, so nested navigation stays reachable.

Prepared locallyUpdated 12:04 UTC

Composition

The shell takes slots, not a configuration object. Sidebar contents, topbar, status bar and the mobile navigation are all ordinary nodes.

<AppShell pathname={pathname} // router-agnostic: a string, not a router renderLink={(props) => <Link {...props} />} sidebarPersistKey="product:sidebar" sidebar={ <> <SidebarHeader>…</SidebarHeader> <SidebarContent ariaLabel="Sections"> <SidebarGroup> <SidebarGroupLabel>Research</SidebarGroupLabel> <SidebarMenu> <SidebarItem label="Datasets" href="/datasets" /> </SidebarMenu> </SidebarGroup> </SidebarContent> <SidebarFooter>…</SidebarFooter> </> } topbar={ <AppShellTopbar> <AppShellMobileTrigger /> <Breadcrumbs items={trail} /> </AppShellTopbar> } statusBar={<AppShellStatusBar>Updated 12:04 UTC</AppShellStatusBar>} > <AppShellContent>{page}</AppShellContent> </AppShell>

What the shell owns

Everything below is a rule, not a preference: a product that follows them cannot produce a shell that fights the system.

Landmarks and keyboard

  • One named navigation landmark per sidebar (the scrolling region is the nav).
  • One main region, one header, one optional status strip.
  • A skip link that is visually hidden until focused and lands on main.
  • Focus returns to the trigger when the mobile drawer closes.

Scroll model

  • Sidebar: its own scroll region, so a long nav never moves the page.
  • Topbar: sticky, opaque, one hairline underneath — never translucent.
  • Main: the document scrolls by default; a workspace pane scrolls itself.
  • Status strip: fixed, and it scrolls sideways rather than wrapping.

API

This page shows components working together rather than exporting one of its own, so the props live on the pages below — each link opens that page's API table.

Luc UI v1.0Overviewdark theme