VisorVisor
Patterns

Dashboard Layout

Responsive app shell — a persistent sidebar on desktop that collapses to a Sheet drawer on mobile — with a top navbar and a content area of cards and tabs.

Preview

Overview

Dashboard

A live snapshot of your workspace — metrics, activity, and anything else worth a glance.

Total revenue

$48,120

+12.4%vs last monthup vs last month

Active users

2,847

+3.1%vs last monthup vs last month

Conversion rate

4.82%

-0.4%vs last monthdown vs last month

Churn

1.2%

0.0%vs last monthflat vs last month

Recent activity

View all
  1. New subscriptionJane Cooper

    Acme Corp upgraded to the Team plan.

    2 minutes ago
  2. User invitedWade Warren

    [email protected] was invited to the workspace.

    18 minutes ago
  3. Payment receivedSystem

    $1,240.00 from Stark Industries.

    1 hour ago
  4. Report exportedEsther Howard

    Q1 revenue report exported as CSV.

    3 hours ago

When to Use

  • Admin dashboards and internal tools
  • Multi-section apps with persistent navigation that must also work on mobile
  • Content-heavy layouts needing sidebar + main area structure
  • Any app shell where the desktop sidebar should collapse to a drawer without duplicating nav markup

Components Used

Structure

<SidebarProvider>
  {/* Desktop sidebar — hidden on mobile via CSS */}
  <Sidebar className="sidebar-desktop">
    <SidebarHeader>
      <h2>App Name</h2>
    </SidebarHeader>
    <SidebarContent>
      <SidebarGroup>
        <SidebarGroupLabel>Main</SidebarGroupLabel>
        <SidebarMenu>
          {navItems.map((item) => (
            <SidebarMenuItem key={item.href}>
              <SidebarMenuButton asChild isActive={pathname === item.href}>
                <a href={item.href}>{item.label}</a>
              </SidebarMenuButton>
            </SidebarMenuItem>
          ))}
        </SidebarMenu>
      </SidebarGroup>
    </SidebarContent>
  </Sidebar>

  <main>
    <Navbar>
      {/* Desktop: collapse the persistent sidebar */}
      <SidebarTrigger className="sidebar-desktop-trigger" />

      {/* Mobile: Sheet drawer sharing the same navItems */}
      <Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
        <SheetTrigger asChild className="sidebar-mobile-trigger">
          <Button variant="ghost" size="icon" aria-label="Open navigation">
            <List />
          </Button>
        </SheetTrigger>
        <SheetContent side="left">
          <SheetHeader>
            <SheetTitle>Navigation</SheetTitle>
          </SheetHeader>
          <nav>
            {navItems.map((item) => (
              <a key={item.href} href={item.href} onClick={() => setMobileOpen(false)}>
                {item.label}
              </a>
            ))}
          </nav>
        </SheetContent>
      </Sheet>

      <Separator orientation="vertical" />
      <span>Dashboard</span>
    </Navbar>

    <ScrollArea>
      <Tabs defaultValue="overview">
        <TabsList>
          <TabsTrigger value="overview">Overview</TabsTrigger>
          <TabsTrigger value="analytics">Analytics</TabsTrigger>
        </TabsList>
        <TabsContent value="overview">
          <div style={{ display: "grid", gap: "var(--spacing-4)", gridTemplateColumns: "repeat(3, 1fr)" }}>
            <Card>
              <CardHeader><CardTitle>Revenue</CardTitle></CardHeader>
              <CardContent>$12,345</CardContent>
            </Card>
            <Card>
              <CardHeader><CardTitle>Users</CardTitle></CardHeader>
              <CardContent>1,234</CardContent>
            </Card>
            <Card>
              <CardHeader><CardTitle>Orders</CardTitle></CardHeader>
              <CardContent>567</CardContent>
            </Card>
          </div>
        </TabsContent>
      </Tabs>
    </ScrollArea>
  </main>
</SidebarProvider>

Notes

  • SidebarProvider manages the collapsed/expanded state and provides context to child components.
  • On desktop the SidebarTrigger toggles the persistent Sidebar; on mobile a Sheet drawer presents the same navItems — use CSS to show/hide the desktop sidebar and the mobile trigger at the appropriate breakpoint, and avoid duplicating navigation markup across the two.
  • Close the Sheet when a nav link is clicked on mobile to avoid stale open state.
  • Use ScrollArea for the main content area to get consistent styled scrollbars.
  • Cards in a CSS Grid layout adapt to the content area width; Tabs organize dashboard views without page navigation.