Skip to content
Component installs need the registry setup
VegaStack Design

app-shell-01

The shell reference — AppShell landmarks and skip link, a rail with search, inbox count, grouped links and a user menu, and linked stat tiles.

Last updated

Skip to content

Overview

What needs you today across Acme.

Your content

Replace this region with the page a route actually renders. Everything around it — the rail, the banner, the skip link — belongs in a shared layout once there is more than one route.

What it is

The application shell reference — AppShell's landmarks and skip link, a rail with search, inbox count, grouped links and a user menu, and a page of linked stat tiles. It is a block: you pull it once with shadcn add, and then you own it — nothing re-pulls it and no integrity hash tracks your edits, unlike the components it composes.

It is the one shell and sidebar reference: every recipe a rail needs is in components/app-sidebar.tsx.

Install

npx shadcn@latest add @vegastack/app-shell-01
Registry setup required
Run this command only after configuring the Base UI shadcn project, the @vegastack registry namespace, and the Cloudflare Access service-token headers in Install from the VegaStack registry.

This installs the block's own files plus the components it composes: app-shell, avatar, breadcrumb, button, card, collapsible, command, dropdown-menu, item, kbd, page-header, provider, sidebar, stat, use-platform.

Preview

Skip to content

Overview

What needs you today across Acme.

Your content

Replace this region with the page a route actually renders. Everything around it — the rail, the banner, the skip link — belongs in a shared layout once there is more than one route.

The rail

  • Workspace menu — the header row is a real DropdownMenu trigger ("Workspace: Acme") with a radio group of workspaces.
  • Search — an outline row that opens a palette on click or on ⌘K / Ctrl+K. The hint is formatShortcut(["mod", "K"], os) from use-platform, marked aria-hidden, and the chord is on the button as aria-keyshortcuts, so the name stays "Search". Swap the palette for command-search-01 when you have search.
  • Inbox — badge and badgeLabel on SidebarMenuButton, so the row is announced as "Inbox 3 unread" and the visual count is decoration.
  • Grouped links under SidebarGroupLabels. isActive on a link row sets aria-current="page".
  • Coming soon — a collapsible row: the Collapsible renders as the SidebarMenuItem, so the menu list keeps only list items, and the row's CollapsibleTrigger carries aria-expanded.
  • User menu — the standard account menu. The footer trigger shows the avatar, name and role; the menu header repeats that row with the email in place of the role. Then Profile and Settings, a Theme submenu (DropdownMenuSub) whose DropdownMenuRadioGroup offers Light · Dark · System with Sun · Moon · Monitor icons and a check on the active one (through useVegaStackTheme), Keyboard shortcuts, a separator, and Sign out. Every item has an icon.

The page

AppShellContent › AppShellPage › PageHeader h1 › linked stat tiles (the stat.mdx "Linked stat tiles" recipe): each count is a whole-tile link to the list it counts, named label first ("Overdue tasks 3").

No flash on a static shell

A statically rendered shell can't read the sidebar cookie on the server. Put SidebarStateScript in the root layout's <head>: it marks the collapsed state before first paint, so the rail doesn't flash open.

import { SidebarStateScript } from "@/components/ui/sidebar";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <SidebarStateScript />
      </head>
      <body>{children}</body>
    </html>
  );
}

Files

FileRegistry typeTarget
app-shell-01/components/app-sidebar.tsxregistry:componentapp/app-shell-01/components/app-sidebar.tsx
app-shell-01/page.tsxregistry:pageapp/app-shell-01/page.tsx

Do / Don't

Do
Hoist the shell into a layout once there is a second route, and keep the count inside the row's name.
Don't
Hand-roll stat cards or a workspace button that opens nothing, or link rows to #.

On this page