Agent docs

Kit: the AppShell gallery

The AppShell gallery, seven real shell shapes behind one tab strip, and a toolbar link that now takes the shape its own contract doc names.

Page and route#

/components/app-shell, also reachable standalone at /shell-demo (a plain re-export outside the gallery layout, apps/playground/src/app/shell-demo/page.tsx:1-3, so the shell can fill the whole viewport). Rendered by AppShellGallery in apps/playground/src/app/components/app-shell/gallery.tsx.

What the reader sees#

One tab strip switching between seven real shell shapes: an interactive playground shell, walmart's actual shell, speedway's actual shell, a collapsed rail, a topbar with every slot filled, a sidebar with counts and a colored group, and a sidebar with footer identity. Below the live shell, a two-column key/value grid restates exactly which props that variant passed, so the picture and the prop list can be checked against each other without opening the source.

Layer 1: shell#

This page IS the shell's own showcase, so "Layer 1" here is the primitive itself, AppShell (packages/ui/src/app-shell), rather than something wrapping the page. The page that hosts the gallery sits inside the playground's own navigation, the standard sidebar-plus-topbar chrome every other playground page shares; the /shell-demo route deliberately opts out of that outer chrome (shell-demo/page.tsx:1-2) so the AppShell instances rendered inside the gallery are not nested inside a second, real shell.

Layer 2: composition#

Every playground page shares one frame: PageFrame (apps/playground/src/app/page-frame.tsx:6-15), a centered max-w-6xl column, and ShowcaseTitle (apps/playground/src/app/showcase-title.tsx:24-40), the icon/title/subtitle/actions header resolved from the route registry. AppShellGallery follows that shape exactly: PageFrame (app-shell/gallery.tsx:127) wraps ShowcaseTitle (:128, with a conditional ThemeToggleButton action only on the standalone /shell-demo route, since that route has no navbar toggle of its own to fall back on), one ExampleCard holding the seven-way tab strip (:130-164), and a SlotMapCard (:166-173).

Layer 3: primitives#

PrimitiveProps as calledfile:lineContract doc
PageFramethe shared max-w-6xl content columnapp-shell/gallery.tsx:127shared across every playground page, not itself a kit export
ShowcaseTitleactions conditional on pathname === "/shell-demo"app-shell/gallery.tsx:124, 128apps/playground/src/app/showcase-title.tsx
ExampleCardtitle="The shell, seven ways", subtitle, toolbar (the "Open full layout" button), source/sourceTitle from the per-variant example fileapp-shell/gallery.tsx:130-145apps/playground/src/app/example-card.tsx
Buttonthe toolbar's "Open full layout in a new tab" link, variant="text" with a trailing Right arrowapp-shell/gallery.tsx:134-143packages/ui/docs/button.md
Tabsitems={VARIANT_ITEMS}, variant="enclosed", size="sm"app-shell/gallery.tsx:148packages/ui/docs/tabs.md
AppShell (×7, inside the example files)one full shell instance per tab: interactive-shell, walmart-shell, speedway-shell (a re-creation, not the live app), collapsed-rail, topbar-search-actions, sidebar-counts-colored-group, sidebar-footer-identityapp-shell/gallery.tsx:150-160, each in its own examples/*.tsxpackages/ui/docs/app-shell.md
SlotMapCardthe four AppShellClassNames slot namesapp-shell/gallery.tsx:166-173apps/playground/src/app/slot-map-card.tsx

Layer 4: patterns#

  • Sidebar anatomy (/patterns/sidebar-anatomy): every one of the seven tabbed shells is, at its core, this pattern (grouped rail, known-only counts, identity footer) with a different combination of AppShell props filled in; the gallery is effectively seven worked instances of the one pattern page, side by side.
  • Not a pattern page but worth naming: app-shell.md's own Travels-with section (app-shell.md:72) calls the auth-boot Skeleton fill for sidebarTop/sidebarFooter "the shell-level half of" the boot-skeleton idea spinner.md documents; this gallery does not demonstrate that boot state, since every tab renders the shell already loaded.

Layer 5: canon rules in force#

  • docs/design-language/08-navigation-and-shell.md §A3 (:21): active state is explicit, never inferred by prefix. The walmart-shell and speedway-shell example files reproduce each app's own active computation rather than a generic placeholder, per app-shell.md:43's Sanctioned-combinations entry.
  • packages/ui/docs/app-shell.md:17: AppShell is not assumed to be the shell for every app on the kit; the speedway-shell tab exists precisely to show the shape speedway built instead, inside the gallery that documents the primitive speedway does not use.
  • docs/design-language/09-page-composition.md §A1: the interactive-shell tab bounds itself to a fixed h-[520px] box (app-shell/gallery.tsx:151) rather than the page's own viewport, so a live, scrollable shell demo can sit inside a reading page without hijacking the whole screen.

Lapses#

Fixed 2026-08-17: the toolbar's navigation button now takes the kit's prescribed shape. app-shell/gallery.tsx:134-143 renders the "Open full layout in a new tab" link as variant="text" color="primary" Icon="Right" iconRight inside the ExampleCard's toolbar slot, the navigation shape button.md:57's Sanctioned entry names and every landing section and the docs home already use. It used to be variant="outline" color="primary" with a hand-typed "↗" appended to the label, which is not the literal banned "bare outline + neutral" of button.md:69 but skirts the same entry's instruction for what a card-toolbar link should be.

A coverage gap, not a defect. The interactive shell tab bounds its demo to h-[520px] and never exercises the AppShell boot state (Skeleton in sidebarTop/sidebarFooter, per app-shell.md's Travels-with section, :72). Walmart's own real boot render is the only place this state is demonstrated today; the gallery could add an eighth tab for it, but nothing in the canon requires one.

See also#

@versable-git/ui · reference, canon, and method, read in place