# Dashboard Layout — Implementation Guide ## Anatomy of a dashboard page A typical dashboard combines stat cards, charts, and data tables: ``` ┌────────────────────────────────────────────────────┐ │ Search / global action bar │ ├──────────┬──────────┬──────────────────────────────┤ │ Stat 1 │ Stat 2 │ Stat 3 │ ├──────────┴──────────┴──────┬───────────────────────┤ │ │ │ │ Data table / list │ Donut chart │ │ (70% width) │ (30% width) │ │ │ │ └────────────────────────────┴───────────────────────┘ ``` --- ## Layout implementation ```tsx import { PageContainer } from "@/components/layout/PageContainer"; import { StatCard } from "@/components/StatCard"; import { DonutChart } from "@/components/DonutChart"; export default function Dashboard() { return (
{/* Search bar */}
{/* global search component */}
{/* Main content: 70/30 split */}
{/* Stat cards row */}
{/* Data table */}
{/* table component */}
{/* Sidebar chart */}
); } ``` --- ## Responsive behavior | Breakpoint | Layout | |------------|--------| | Mobile (`< 768px`) | Single column, everything stacked | | Tablet (`md`) | Stat cards in 3-col grid, rest stacked | | Desktop (`lg`) | 70/30 split for table + chart | Key Tailwind classes: ``` grid grid-cols-1 lg:grid-cols-[70%_30%] gap-6 grid grid-cols-1 md:grid-cols-3 gap-6 ``` --- ## Loading state Show a full-page loading state while dashboard data is being fetched: ```tsx if (loading) { return (

Loading dashboard…

); } ``` Or use a skeleton layout: ```tsx if (loading) { return (
{[1, 2, 3].map((i) => (
))}
); } ``` --- ## Data fetching pattern Use `useEffect` with cancellation for dashboard metrics: ```ts const [metrics, setMetrics] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; (async () => { try { setLoading(true); const data = await fetchDashboardMetrics(); if (!cancelled) setMetrics(data); } catch (error) { if (!cancelled) console.error("Error loading metrics:", error); } finally { if (!cancelled) setLoading(false); } })(); return () => { cancelled = true; }; }, []); ``` --- ## Combining multiple data sources Dashboards often aggregate data from several APIs. Load them in parallel: ```ts const [metrics, setMetrics] = useState(null); const [requests, setRequests] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; Promise.all([fetchMetrics(), fetchRecentRequests()]) .then(([metricsData, requestsData]) => { if (!cancelled) { setMetrics(metricsData); setRequests(requestsData); } }) .catch((err) => { if (!cancelled) console.error(err); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, []); ``` --- ## PageContainer wrapper A simple wrapper for consistent page padding: ```tsx interface PageContainerProps { children: React.ReactNode; } export function PageContainer({ children }: PageContainerProps) { return
{children}
; } ```