Skip to Content
PatternsDashboard

Dashboard

The dashboard pattern is used for overview pages that aggregate data into summaries, charts, and quick actions. Examples include the weather dashboard, news overview, and event analytics.

Anatomy

A dashboard page consists of:

  1. Header — page title, date range picker, and global actions
  2. Stats row — key metrics displayed as stat cards
  3. Primary chart — the main data visualization
  4. Secondary panels — supporting charts, tables, or activity feeds
  5. Quick actions — shortcuts to common tasks

Layout

Use the DashboardLayout component for the sidebar + content structure:

<DashboardLayout> <MukokoSidebar /> <main className="flex-1 p-4 sm:p-6"> {/* Header */} <div className="flex items-center justify-between"> <h1 className="font-serif text-2xl font-bold">Dashboard</h1> <DatePicker /> </div> {/* Stats */} <div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-4"> <StatsCard title="Total views" value="12,345" change="+12%" /> <StatsCard title="Active users" value="1,234" change="+5%" /> <StatsCard title="Revenue" value="$8,901" change="+8%" /> <StatsCard title="Events" value="42" change="+3%" /> </div> {/* Charts */} <div className="mt-6 grid gap-4 lg:grid-cols-[2fr_1fr]"> <Card>{/* Primary chart */}</Card> <Card>{/* Secondary panel */}</Card> </div> </main> </DashboardLayout>

Stats cards

Use the StatsCard component for key metrics:

<StatsCard title="Total events" value="1,247" change="+12%" description="Compared to last month" />

Arrange stats in a responsive grid that collapses on mobile:

<div className="grid gap-4 grid-cols-2 lg:grid-cols-4"> <StatsCard title="Views" value="12.3K" /> <StatsCard title="Users" value="1.2K" /> <StatsCard title="Revenue" value="$8.9K" /> <StatsCard title="Growth" value="+12%" /> </div>

Chart integration

Use the chart component with Recharts for data visualization. Charts automatically use the Five African Minerals chart tokens:

const chartConfig = { views: { label: "Views", color: "var(--chart-1)" }, users: { label: "Users", color: "var(--chart-2)" }, } <ChartContainer config={chartConfig} className="h-[300px]"> <AreaChart data={data}> <Area dataKey="views" fill="var(--chart-1)" stroke="var(--chart-1)" /> <Area dataKey="users" fill="var(--chart-2)" stroke="var(--chart-2)" /> <ChartTooltip content={<ChartTooltipContent />} /> </AreaChart> </ChartContainer>

Grid patterns

Two-column with emphasis

Large chart on the left, narrow panel on the right:

<div className="grid gap-4 lg:grid-cols-[2fr_1fr]"> <Card className="p-6">{/* Primary chart */}</Card> <Card className="p-6">{/* Activity feed or secondary chart */}</Card> </div>

Three-column equal

<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"> <Card className="p-6">{/* Chart 1 */}</Card> <Card className="p-6">{/* Chart 2 */}</Card> <Card className="p-6">{/* Chart 3 */}</Card> </div>

Mobile dashboards

On mobile, dashboards stack vertically. Prioritize information:

  1. Stats cards — always visible (2-column grid on mobile)
  2. Primary chart — full width
  3. Secondary panels — below, in order of importance
  4. Data tables — use horizontal scroll or switch to card view
{/* Responsive table/card switch */} <div className="hidden sm:block"> <DataTable columns={columns} data={data} /> </div> <div className="sm:hidden space-y-3"> {data.map((item) => ( <Card key={item.id} className="p-4"> <p className="font-medium">{item.name}</p> <p className="text-sm text-muted-foreground">{item.value}</p> </Card> ))} </div>

Refresh and real-time

For dashboards that update periodically:

  • Show the last refresh time in the header
  • Use skeleton loading for sections that are refreshing
  • Avoid full-page loading states — update individual sections independently
Last updated on