AppShell
A full-page application shell that composes a fixed Header, a left Navbar, a right Aside, a Footer, and a scrollable Main content area. All sections are optional — include only what you need. The layout automatically adjusts Main's padding so content is never hidden behind fixed panels.
AppShell is typically used once at the root layout of your application.
Layout structure
Visual map of where each subcomponent lives in the viewport.
Full layout
import { AppShell, Burger, ScrollArea } from '@davaux/ui'
<AppShell
header={{ height: 56 }}
navbar={{ width: 260, breakpoint: 'md', burgerId: 'my-burger' }}
aside={{ width: 200 }}
footer={{ height: 40 }}
withBorder
>
<AppShell.Header>
<Burger id="my-burger" />
<span>My App</span>
</AppShell.Header>
<AppShell.Navbar>
<ScrollArea style="flex:1;min-height:0">
{/* nav links */}
</ScrollArea>
</AppShell.Navbar>
<AppShell.Main>
{/* page content */}
</AppShell.Main>
<AppShell.Aside>
{/* aside content */}
</AppShell.Aside>
<AppShell.Footer>
<span>© 2025</span>
</AppShell.Footer>
</AppShell>Navbar only
Omit any subcomponent you don't need. Here footer and aside are omitted.
<AppShell
header={{ height: 56 }}
navbar={{ width: 260, breakpoint: 'sm' }}
withBorder
>
<AppShell.Header>...</AppShell.Header>
<AppShell.Navbar>...</AppShell.Navbar>
<AppShell.Main>...</AppShell.Main>
</AppShell>Alt layout
layout="alt" makes the navbar and aside span the full viewport height instead of sitting between the header and footer.
<AppShell layout="alt" navbar={{ width: 260 }} header={{ height: 56 }}>
...
</AppShell>Mobile navbar with Burger
Set navbar.breakpoint to a size token. Below that viewport width the navbar becomes a slide-in overlay. Wire a Burger by passing its id to navbar.burgerId — the AppShell's inline script connects them automatically.
<AppShell
navbar={{ width: 260, breakpoint: 'md', burgerId: 'nav-burger' }}
header={{ height: 56 }}
>
<AppShell.Header>
{/* Burger is hidden on desktop via CSS, visible below the breakpoint */}
<Burger id="nav-burger" aria-label="Toggle navigation" />
<span>My App</span>
</AppShell.Header>
<AppShell.Navbar>...</AppShell.Navbar>
<AppShell.Main>...</AppShell.Main>
</AppShell>Collapsed desktop navbar
Pass collapsed.desktop: true to start with the navbar hidden on desktop. The inline script and burger button toggle it open/closed.
<AppShell
navbar={{
width: 260,
breakpoint: 'md',
burgerId: 'nav-burger',
collapsed: { desktop: true },
}}
header={{ height: 56 }}
>
...
</AppShell>AppShell.Section
Use AppShell.Section inside AppShell.Navbar or AppShell.Aside to divide the sidebar into fixed-height and scrollable regions. Sections support Style Props, so padding can be applied with shorthand props like p="md".
<AppShell.Navbar>
{/* Fixed top area — e.g. a search input */}
<AppShell.Section style="padding: var(--dv-spacing-md)">
<input placeholder="Search..." />
</AppShell.Section>
{/* Scrollable nav links — grows to fill remaining space */}
<AppShell.Section grow>
<ScrollArea style="height:100%">
<nav>{/* links */}</nav>
</ScrollArea>
</AppShell.Section>
{/* Fixed bottom area — e.g. user profile */}
<AppShell.Section style="padding: var(--dv-spacing-md)">
<UserProfile />
</AppShell.Section>
</AppShell.Navbar>Scrollable navbar / aside
Add scrollable to AppShell.Navbar or AppShell.Aside to automatically wrap the children in a ScrollArea that fills the available height. Use this when the sidebar has a single scrollable region. For the fixed-header + scrollable-middle + fixed-footer pattern, leave scrollable unset and compose with AppShell.Section and ScrollArea manually.
{/* Simple — single scrollable region */}
<AppShell.Navbar scrollable>
<nav>{/* links */}</nav>
</AppShell.Navbar>
{/* Flexible — fixed top/bottom, scrollable middle */}
<AppShell.Navbar>
<AppShell.Section p="md">
<input placeholder="Search..." />
</AppShell.Section>
<AppShell.Section grow>
<ScrollArea style="height:100%">
<nav>{/* links */}</nav>
</ScrollArea>
</AppShell.Section>
<AppShell.Section p="md">
<UserProfile />
</AppShell.Section>
</AppShell.Navbar>Non-sticky footer
By default AppShell.Footer renders in document flow below Main and scrolls with the page — no footer config needed on AppShell. Add sticky to fix it to the bottom of the viewport instead; in that case also pass footer={ height } so Main and the Navbar reserve the correct space.
{/* Non-sticky footer (default) — no footer config needed */}
<AppShell ...>
<AppShell.Main>...</AppShell.Main>
<AppShell.Footer>
<span>© 2025</span>
</AppShell.Footer>
</AppShell>
{/* Sticky footer — reserve height in the AppShell config */}
<AppShell footer={{ height: 40 }} ...>
<AppShell.Footer sticky>
<span>© 2025</span>
</AppShell.Footer>
</AppShell>Surface elevation
Each subcomponent accepts a surface prop (0–5) that maps to the global --dv-surface-N CSS token. The defaults reflect a natural depth hierarchy — Main sits at surface 0 (page canvas), Navbar and Aside at 1 (raised panel), and Header and Footer at 2. Override any part to shift it up or down the elevation scale.
{/* Raise the navbar one level above default */}
<AppShell.Navbar surface={2}>...</AppShell.Navbar>
{/* Drop the header to match the navbar */}
<AppShell.Header surface={1}>...</AppShell.Header>Responsive padding
Pass a breakpoint object to padding to use different spacing at different viewport widths. Keys follow the same size tokens as breakpoint — unspecified breakpoints inherit from the nearest smaller one.
<AppShell padding={{ base: 'sm', md: 'xl' }} ...>
...
</AppShell>Custom transition
The navbar and aside slide-in animation defaults to 250ms. Pass transitionDuration to speed it up, slow it down, or set it to 0 to disable it.
<AppShell transitionDuration={400} ...>
...
</AppShell>Custom Main element
AppShell.Main renders as <main> by default. Pass component to change the element — useful when <main> is used elsewhere on the page.
<AppShell.Main component="div">
{/* page content */}
</AppShell.Main>Burger button
The Burger component is a standalone button — see the Burger docs for its own props. AppShell does not manage its opened state: the inline script on the shell root handles all toggling by reading and writing data-navbar-opened / data-aside-opened attributes directly on the shell element.
AppShell props
| Prop | Type | Default | Description |
|---|---|---|---|
header | AppShellHeaderConfig | — | Enables the fixed header. Requires height. |
footer | { height: number | string } | — | Reserves viewport space for a fixed footer. Only needed when AppShell.Footer is sticky (the default). Omit when using sticky={false}. |
navbar | AppShellNavbarConfig | — | Enables the left sidebar. Requires width. |
aside | AppShellAsideConfig | — | Enables the right sidebar. Requires width. |
padding | 'xs'|'sm'|'md'|'lg'|'xl'|number|string|AppShellPaddingBreakpoints | 'md' | Inner padding applied to AppShell.Main. Pass a breakpoint object for responsive values. |
layout | 'default' | 'alt' | 'default' | 'alt': navbar and aside span full viewport height. |
withBorder | boolean | true | Adds borders between header, footer, navbar, and aside. |
zIndex | number | 100 | Base z-index. Header/footer = base+2, navbar/aside = base+1. |
transitionDuration | number | 250 | Navbar/aside slide animation duration in ms. Set to 0 to disable. |
id | string | 'dv-app-shell' | ID of the root element (used by the burger toggle script). |
class | string | — | Additional CSS class names. |
style | object | — | Inline styles on the root element. |
AppShellNavbarConfig
| Key | Type | Default | Description |
|---|---|---|---|
width | number | string | — | Width of the navbar (number = px, string = any CSS value). |
breakpoint | 'xs'|'sm'|'md'|'lg'|'xl' | — | Viewport width below which the navbar becomes a slide-in overlay. |
collapsed.desktop | boolean | — | Start collapsed on desktop. |
collapsed.mobile | boolean | — | Start collapsed on mobile (overlay hidden). |
burgerId | string | — | ID of the Burger button that controls the navbar overlay. |
AppShellAsideConfig
| Key | Type | Default | Description |
|---|---|---|---|
width | number | string | — | Width of the aside (number = px, string = any CSS value). |
breakpoint | 'xs'|'sm'|'md'|'lg'|'xl' | — | Viewport width below which the aside becomes a slide-in overlay. |
collapsed.desktop | boolean | — | Start collapsed on desktop. |
collapsed.mobile | boolean | — | Start collapsed on mobile (overlay hidden). |
burgerId | string | — | ID of a button that controls the aside overlay. |
Breakpoint reference
| Token | Max-width |
|---|---|
'xs' | 30em (480 px) |
'sm' | 40em (640 px) |
'md' | 48em (768 px) |
'lg' | 62em (992 px) |
'xl' | 75em (1200 px) |
Subcomponent props
All subcomponents support Style Props as well as class, style, and children. The table below lists only the props unique to each subcomponent.
| Subcomponent | Prop | Type | Default | Description |
|---|---|---|---|---|
AppShell.Header | sticky | boolean | false | When true, fixes the header to the top of the viewport. |
AppShell.Header | surface | 0–5 | 2 | Surface elevation level. Controls the background via --dv-surface-N. |
AppShell.Footer | sticky | boolean | false | When true, fixes the footer to the bottom of the viewport. Requires footer={ height } on AppShell to reserve space. |
AppShell.Footer | surface | 0–5 | 2 | Surface elevation level. Controls the background via --dv-surface-N. |
AppShell.Navbar | scrollable | boolean | — | Wraps children in a ScrollArea that fills available height. |
AppShell.Navbar | surface | 0–5 | 1 | Surface elevation level. Controls the background via --dv-surface-N. |
AppShell.Aside | scrollable | boolean | — | Wraps children in a ScrollArea that fills available height. |
AppShell.Aside | surface | 0–5 | 1 | Surface elevation level. Controls the background via --dv-surface-N. |
AppShell.Main | component | string | 'main' | HTML element to render as the root node. |
AppShell.Main | surface | 0–5 | 0 | Surface elevation level. Controls the background via --dv-surface-N. |
AppShell.Section props
Supports Style Props for shorthand inline style manipulation.
| Prop | Type | Default | Description |
|---|---|---|---|
grow | boolean | false | Expands the section to fill remaining space in the sidebar column. |
class | string | — | Additional CSS class names. |
style | object | — | Inline styles. |
children | any | — | Section content. |