All components
App Shell
The top-level application frame composing a navbar, sidebar, and main content area.
Acme
1234567891011121314151617import { AppShell, appShellFullscreen } from "#components/ui/base-ui/app-shell.tsx";import { Navbar } from "#components/ui/base-ui/navbar.tsx";import { Sidebar } from "#components/ui/base-ui/sidebar.tsx";
export function Example() { return ( // Root stacks the navbar over Content, which lays the sidebar next to // Main; pin it to the viewport with style={appShellFullscreen} <AppShell.Root> <Navbar.Root>{/* navbar */}</Navbar.Root> <AppShell.Content> <Sidebar.Root>{/* sidebar */}</Sidebar.Root> <AppShell.Main>{/* page */}</AppShell.Main> </AppShell.Content> </AppShell.Root> );}Install
1npx stylexblocks add app-shellSource
components/ui/base-ui/app-shell.tsx
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667import * as stylex from "@stylexjs/stylex";import { createSlotRecipeContext } from "#lib/base-ui/create-slot-recipe-context.tsx";import { defineSlotRecipe } from "#lib/recipe-props.ts";const appShellRoot = stylex.create({ base: { display: 'flex', flexDirection: 'column', height: '100dvh', },})
const appShellRootFullscreens = stylex.create({ true: { position: 'fixed', inset: 0, },})
const appShellContent = stylex.create({ base: { display: 'flex', flex: 1, minWidth: 0, minHeight: 0, },})
const appShellMain = stylex.create({ base: { display: 'flex', flex: 1, flexDirection: 'column', minWidth: 0, },})
export type AppShellFullscreen = keyof typeof appShellRootFullscreens
// defineSlotRecipe validates the shape at compile time. The generated// fullscreen map is a boolean overlay with no `false` counterpart to default// to, so it is exported as a composable style instead of a variant axis.const appShellSlotRecipe = defineSlotRecipe({ slots: { root: { styles: appShellRoot }, content: { styles: appShellContent }, main: { styles: appShellMain }, }, defaultVariants: {},});
/** * AppShell — recipe and component colocated in one file; each part composes * via `render`. Root stacks a navbar over Content, which lays a sidebar * next to Main. Pin the shell to the viewport with * `<AppShell.Root style={appShellFullscreen}>`. */const { withProvider, withContext } = createSlotRecipeContext(appShellSlotRecipe);
export const appShellFullscreen = appShellRootFullscreens.true;
export const AppShell = { Root: withProvider("div", "root", "AppShellRoot"), Content: withContext("div", "content", "AppShellContent"), Main: withContext("main", "main", "AppShellMain"),};