Dashboard Layout Pattern
Live PreviewOpen in Storybook ↗
A persistent sidebar + top bar layout is the foundation of almost every admin or SaaS application. This pattern shows how to compose prokodo UI's Sidenav, Tabs, and layout primitives into a full App Router dashboard shell.
When to use this pattern
- Internal tools, admin panels, and SaaS dashboards
- Any multi-section app where persistent navigation reduces context-switching
- When you need breadcrumbs or a section-level tab bar alongside a global sidebar
Structure
app/
(dashboard)/
layout.tsx ← dashboard shell (Server Component)
page.tsx ← overview page
settings/
page.tsx
analytics/
page.tsx
Shell layout
app/(dashboard)/layout.tsx
import { Sidenav } from "@prokodo/ui/sidenav"
import "@prokodo/ui/sidenav.css"
const navItems = [
{
label: "Overview",
redirect: { href: "/" },
icon: { name: "HomeOutlinedIcon" },
},
{
label: "Analytics",
redirect: { href: "/analytics" },
icon: { name: "BarChartOutlinedIcon" },
},
{
label: "Settings",
redirect: { href: "/settings" },
icon: { name: "SettingsOutlinedIcon" },
},
]
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div style={{ display: "flex", minHeight: "100vh" }}>
<Sidenav items={navItems} />
<main style={{ flex: 1, padding: "2rem", overflowY: "auto" }}>
{children}
</main>
</div>
)
}
Section tabs
Use Tabs inside page-level components for secondary navigation:
app/(dashboard)/analytics/page.tsx
import { Tabs } from "@prokodo/ui/tabs"
import "@prokodo/ui/tabs.css"
const tabs = [
{ value: "traffic", label: "Traffic", content: <TrafficPanel /> },
{ value: "conversion", label: "Conversion", content: <ConversionPanel /> },
{ value: "revenue", label: "Revenue", content: <RevenuePanel /> },
]
export default function AnalyticsPage() {
return (
<>
<h1>Analytics</h1>
<Tabs
id="analytics-tabs"
ariaLabel="Analytics sections"
items={tabs}
defaultValue="traffic"
/>
</>
)
}
Responsive behaviour
On mobile the Sidenav collapses to a drawer. No extra code is required — the component handles this via an internal useMediaQuery hook. The breakpoint is not configurable via a CSS variable.
Related components
Sidenav— collapsible, icon-only, and mobile-drawer variantsTabs— keyboard-accessible tab barDrawer— full-screen mobile menu overlay
Further reading
- Next.js Layouts & Templates
- prokodo Next.js agency — we build and maintain production Next.js dashboards