EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
AppShell·component·@astryxdesign/core

App Shell

AppShell is the page shell for an application. It provides slots for top navigation, side navigation, banners, and main content. Use it as the root wrapper for every page. It handles responsive mobile navigation and skip-to-content automatically. Configure side nav collapse on SideNav with its collapsible prop.

Open in Playground @astryxdesign/core/AppShell

Showcases and examples

6 documented examples

App Shell

A basic app shell with content padding.

Preview loads on approachPreview loads on approach
Exact source · app-shell-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {AppShell} from '@astryxdesign/core/AppShell';
import {VStack} from '@astryxdesign/core/Stack';
import {Heading, Text} from '@astryxdesign/core/Text';
import {NavIcon} from '@astryxdesign/core/NavIcon';
import {
  SideNav,
  SideNavHeading,
  SideNavItem,
  SideNavSection,
} from '@astryxdesign/core/SideNav';
import {
  ChartBarIcon,
  DocumentTextIcon,
  UsersIcon,
} from '@heroicons/react/24/outline';
import {HomeIcon} from '@heroicons/react/24/solid';
import {CubeIcon} from '@heroicons/react/24/outline';

export default function AppShellShowcase() {
  return (
    <AppShell
      contentPadding={6}
      style={{height: '100%', minHeight: 0, width: '100%'}}
      sideNav={
        <SideNav
          header={
            <SideNavHeading
              icon={
                <NavIcon icon={<CubeIcon style={{width: 16, height: 16}} />} />
              }
              heading="App Shell"
              headingHref="#"
            />
          }>
          <SideNavSection title="Main" isHeaderHidden>
            <SideNavItem label="Home" icon={HomeIcon} isSelected href="#" />
            <SideNavItem label="Reports" icon={ChartBarIcon} href="#" />
            <SideNavItem label="Documents" icon={DocumentTextIcon} href="#" />
            <SideNavItem label="Team" icon={UsersIcon} href="#" />
          </SideNavSection>
        </SideNav>
      }>
      <VStack gap={4}>
        <Heading level={3}>Page Content</Heading>
        <Text type="body">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
          eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
          minim veniam, quis nostrud exercitation ullamco laboris.
        </Text>
      </VStack>
    </AppShell>
  );
}

Usage

AppShell is the page shell for an application. It provides slots for top navigation, side navigation, banners, and main content. Use it as the root wrapper for every page. It handles responsive mobile navigation and skip-to-content automatically. Configure side nav collapse on SideNav with its collapsible prop.

  • Choose the right height: use "fill" for dashboards with internal scrolling and "auto" for pages that grow with content.
  • Set contentPadding based on content type: 4 for forms and settings, 0 for tables and dashboards.
  • Give every nav slot an accessible name. AppShell renders TopNav and SideNav as separate navigation landmarks, and a screen reader lists them by name, so pass label to each one.
  • Start the page heading inside children. AppShell owns the skip link, the banner landmark and the main landmark, but it renders no heading, so the first heading in the content area is the page h1.
  • Nest one AppShell inside another; it's the outermost layout frame.
  • Use for sub-page layouts; use Layout for content areas within AppShell.
  • Add your own skip link or <main> element. AppShell already renders both, and a second main landmark makes the first ambiguous.

Typed props

PropType and behavior
childrenReactNode
Main content area, rendered inside a <main> element.
contentPadding0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10 · default 0
Padding for the main content area. Set based on the dominant content pattern: 4 (16px) for forms/settings/text, 0 for dashboards/maps/tables. Override individual sections with Section.
topNavReactNode
Top navigation slot, typically TopNav.
Slot: TopNav
sideNavReactNode
Side navigation slot, typically SideNav.
Slot: SideNav
mobileNavReactNode
Mobile navigation configuration. Accepts false (disable), a config object (tune auto behavior), or ReactNode (full custom drawer). The config object is {hasToggle?: boolean, isOpen?: boolean, onOpenChange?: (isOpen: boolean) => void, content?: ReactNode, breakpoint?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'none', defaultIsMobile?: boolean}; breakpoint defaults to 'md', resolves through the nearest Theme's widthBreakpoints, and switches to the wider layout at equality. 'none' is always non-mobile and ignores defaultIsMobile.
Slot: MobileNav
bannerReactNode
Banner slot for system-wide announcements, placed above the topNav.
Slot: Banner
height'fill' | 'auto' · default 'fill'
Height behavior: 'fill' makes the shell fill the viewport (100dvh) with independent scroll containers; 'auto' lets the shell grow with content and uses sticky positioning for nav.
variant'wash' | 'surface' | 'section' | 'elevated' · default 'elevated'
Navigation background style controlling how nav areas contrast with content. 'wash' uses wash background, 'surface' uses surface background, 'section' adds dividers between nav and content, 'elevated' uses wash nav with elevated surface content and border radius.
xstyleStyleXStyles
StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value, not an inline style object like style={{}}.

Anatomy

Page shell · required

Outermost application frame that owns page-level navigation, responsive shell behavior, and the main content landmark.

Skip link · required

First focusable element on the page. Visually hidden until focused, then moves focus to the main content area.

Banner · optional

The banner slot, for system-wide announcements. Renders above the top nav, inside the banner landmark.

Top navigation · optional

The topNav slot, typically TopNav. Below the mobile breakpoint it becomes a compact bar carrying the nav toggle.

Side navigation · optional

The sideNav slot, typically SideNav. Inline above the breakpoint, moved into the mobile drawer below it.

Main content · required

children, rendered in the main landmark. Scrolls internally when height is fill, and with the page when it is auto.

Mobile nav drawer · optional

Generated below the breakpoint from the nav slots unless mobileNav disables or replaces it. A modal dialog: it traps focus and returns focus to the toggle on close.

Theming

Targets

astryx-app-shell

Visual props: variant

astryx-app-shell-header

Visual props: variant

astryx-app-shell-sidenav

Visual props: variant