Component
AppShell
AppShell provides placement regions for mobile application chrome and a separately scrolling body. Put visual components such as NavigationBar and TabBar inside its header and footer regions.
Preview
Installation
pnpm dlx shadcn@latest add https://pwaui.com/r/app-shell.jsonUsage
import { Home } from "lucide-react"import { AppShell } from "@/components/ui/app-shell"import { NavigationBar } from "@/components/ui/navigation-bar"import { TabBar } from "@/components/ui/tab-bar"
export function Screen() { return ( <AppShell> <AppShell.Header> <NavigationBar> <NavigationBar.Title>Today</NavigationBar.Title> </NavigationBar> </AppShell.Header> <AppShell.Main>Scrollable content</AppShell.Main> <AppShell.Footer keyboardBehavior="hide"> <TabBar> <TabBar.Item icon={<Home />} label="Home" active /> </TabBar> </AppShell.Footer> </AppShell> )}Anatomy
AppShellAppShell.HeaderAppShell.MainAppShell.FooterComposition
See how PWAProvider, AppShell, SafeArea, NavigationBar, and TabBar divide viewport, scrolling, safe-area, and navigation responsibilities.
Behavior notes
- Header and Footer are placement regions, not styled navigation components.
- The usual composition is NavigationBar inside Header and TabBar inside Footer.
- For a full-screen application, opt into root containment so Main is the only vertical scroll region.
- Header and Footer apply the relevant safe-area inset; do not wrap their children in another SafeArea for the same edge.
- Main owns scrolling and overscroll containment.
- Footer keyboardBehavior can leave chrome in place or hide it while the software keyboard is open when PWAProvider is mounted.
Platform limitations
--pwa-viewport-heighttracks the visual viewport and shrinks when the software keyboard opens. Anchor chrome with the safe-area padding this component applies rather than100vh.- Safe-area insets are only non-zero with
viewport-fit=coveron edge-to-edge or installed surfaces. In an ordinary browser tab they resolve to 0.
Accessibility
Uses semantic header, main, and footer elements. Provide accessible navigation landmarks inside the chrome regions.