# App Shell

> Sidebar, topbar and a live overview — the whole app frame.

A shadcn/ui block from the [@blockforge](https://blockforge.terravidhal.me) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/blockforge/app-shell).

- Page, with a live preview: https://shadcn.exchange/r/blockforge/app-shell
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/blockforge/app-shell-light-b7a954f20c2a8fbf.png
- Registry item: https://blockforge.terravidhal.me/r/app-shell.json
- Categories: app
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://blockforge.terravidhal.me/r/app-shell.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`

## Files

### `registry/blocks/app-shell.tsx`

```tsx
import {
  Bell,
  CircleGauge,
  Folder,
  LifeBuoy,
  Rocket,
  Search,
  Settings,
  Users,
} from "lucide-react";

import { cn } from "@/lib/utils";

const navigation = [
  { label: "Overview", icon: CircleGauge, active: true },
  { label: "Deployments", icon: Rocket, active: false },
  { label: "Projects", icon: Folder, active: false },
  { label: "Team", icon: Users, active: false },
  { label: "Settings", icon: Settings, active: false },
];

const deploys = [
  { project: "marketing-site", env: "production", status: "Ready", time: "2m ago" },
  { project: "api-gateway", env: "production", status: "Building", time: "6m ago" },
  { project: "docs", env: "preview", status: "Ready", time: "31m ago" },
];

export default function AppShell() {
  return (
    <section className="flex min-h-[640px] bg-background">
      {/* Sidebar */}
      <aside className="hidden w-56 shrink-0 flex-col border-r border-border/60 md:flex">
        <div className="flex h-14 items-center gap-2 border-b border-border/60 px-4 font-semibold">
          <span className="flex size-6 items-center justify-center rounded-md bg-foreground font-mono text-xs text-background">
            A
          </span>
          Acme
        </div>
        <nav className="flex-1 space-y-0.5 p-2">
          {navigation.map((item) => (
            <a
              key={item.label}
              href="#"
              aria-current={item.active ? "page" : undefined}
              className={cn(
                "flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm transition-colors",
                item.active
                  ? "bg-accent font-medium"
                  : "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
              )}
            >
              <item.icon className="size-4" />
              {item.label}
            </a>
          ))}
        </nav>
        <div className="border-t border-border/60 p-2">
          <a
            href="#"
            className="flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
          >
            <LifeBuoy className="size-4" />
            Support
          </a>
        </div>
      </aside>

      {/* Main */}
      <div className="flex min-w-0 flex-1 flex-col">
        {/* Topbar */}
        <header className="flex h-14 items-center gap-3 border-b border-border/60 px-4">
          <p className="text-sm font-medium">Overview</p>
          <div className="ml-auto flex items-center gap-2">
            <div className="hidden h-8 items-center gap-2 rounded-lg border border-input px-2.5 text-sm text-muted-foreground sm:flex">
              <Search className="size-3.5" />
              Search
              <kbd className="rounded-sm border border-border/60 bg-muted px-1.5 font-mono text-[10px]">
                ⌘K
              </kbd>
            </div>
            <button
              type="button"
              aria-label="Notifications"
              className="flex size-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
            >
              <Bell className="size-4" />
            </button>
            <span className="flex size-8 items-center justify-center rounded-full bg-muted font-mono text-xs font-semibold text-muted-foreground">
              NB
            </span>
          </div>
        </header>

        {/* Content */}
        <div className="grid gap-4 p-4 sm:p-6">
          <div className="grid gap-4 sm:grid-cols-3">
            {[
              { label: "Deployments today", value: "128" },
              { label: "Error rate", value: "0.02%" },
              { label: "p95 build time", value: "48s" },
            ].map((stat) => (
              <div
                key={stat.label}
                className="rounded-xl border border-border/60 bg-card p-4"
              >
                <p className="text-xs text-muted-foreground">{stat.label}</p>
                <p className="mt-1.5 text-2xl font-semibold tracking-tight tabular-nums">
                  {stat.value}
                </p>
              </div>
            ))}
          </div>

          <div className="overflow-hidden rounded-xl border border-border/60">
            <div className="border-b border-border/60 bg-card px-4 py-3 text-sm font-medium">
              Recent deployments
            </div>
            {deploys.map((deploy) => (
              <div
                key={deploy.project}
                className="flex items-center justify-between border-b border-border/60 px-4 py-3 last:border-b-0"
              >
                <div className="flex items-center gap-3">
                  <span
                    className={cn(
                      "size-2 rounded-full",
                      deploy.status === "Ready"
                        ? "bg-emerald-500"
                        : "bg-amber-500 animate-status",
                    )}
                  />
                  <span className="font-mono text-sm">{deploy.project}</span>
                  <span className="rounded-md bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground">
                    {deploy.env}
                  </span>
                </div>
                <span className="font-mono text-xs text-muted-foreground">
                  {deploy.time}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}
```
