Skip to content
How-To Pattern 06 of 6

Management Dashboard

The densest cookbook pattern — metric cards, activity table, and quota indicators combined. Shows how Card, Table, TabGroup, Badge, Alert, and Progress fit together.

Operations Overview

Snapshot across the selected range

Active users
8,412+12%

vs. previous period

Sessions
24,390+4%

vs. previous period

Revenue
$42,108-2%

vs. previous period

Avg. response
184 ms+18 ms

P95 across edges

Recent Activity

UserActionStatusTime
alex@acme.devRotated API keySuccess2m ago
maria@acme.devInvited new memberPending14m ago
deploy-botPushed build v3.2.1Success1h ago
lee@acme.devRemoved webhookFailed2h ago

Plan Usage

API requests87%
Storage42%
Seats9 / 12

Visual reference

Storybook captures of this pattern in each framework, light and dark modes. The live demo above runs in React; these confirm the Angular and Vue compositions render the same way.

Management Dashboard in Angular, light mode
Light
Management Dashboard in Angular, dark mode
Dark

When to use

  • Operational overview pages: metric cards above, table of recent activity below, supplementary indicators (quota, plan usage) on the side.
  • Dashboards with a global time-range selector that re-scopes every widget — TabGroup with `variant="pills"` is the right control.
  • When the user needs to triage at a glance and only drill in if a metric is anomalous (warning Alert above the threshold).

When not to use

  • Single-metric pages — all this scaffolding is overkill for one number with a sparkline.
  • Pages where the data is the whole point and side-by-side cards add no value — render the table full-bleed instead.
  • Real-time dashboards with sub-second updates — these fight the static layout; use an SVG/canvas chart and drop the Card grids.

Accessibility

  • LlmProgress for quota uses `role="progressbar"` with `aria-valuenow` — don't add a duplicate visible-text-only readout for screen readers; the role surfaces the value automatically.
  • The metric card delta uses a Badge whose colour encodes direction. Pair every coloured delta with a `+` / `-` glyph so the meaning survives without colour.
  • Recent-activity table's status column is colour-only when read alone — keep the textual label ("Success", "Pending", "Failed") inside the Badge.

See the accessibility overview for the site-wide WCAG stance and per-component focus / ARIA notes.

Common pitfalls

What an LLM most commonly produces wrong here.

  • LLMs love to project tab content into a giant `ngSwitch` / ternary that re-renders the entire grid on each tab change. Bind only the data-fetch scope to the tab; let the layout stay static.
  • Using `variant="warning"` Alerts for every quota above 50 % numbs the signal. Reserve for crossings of the actual SLA / billing threshold.
  • Putting the table and the side panel into a single LlmCard collapses their independent scroll regions. They're siblings, not parent/child.

Variations

With drill-down per metric

Add an `onClick` that opens an LlmDrawer with the metric's history — Drawer keeps the dashboard context, Dialog would dim it.

Empty state

When no activity exists, replace the table with a centered LlmAlert + LlmButton ("Invite your first member") inside the same Card.

Code

Snippets are intentionally trimmed for readability. The full implementation — with state, styles, and demo data — lives in the framework Storybook files linked below.

<!-- Metric cards + activity table + quota widget.
Uses Card, Table, TabGroup, Badge, Alert, Progress. -->
<llm-tab-group variant="pills" [(selectedIndex)]="range">
<llm-tab label="7D" />
<llm-tab label="30D" />
<llm-tab label="90D" />
</llm-tab-group>
@if (quota() >= 85) {
<llm-alert variant="warning">API quota at {{ quota() }}%.</llm-alert>
}
<!-- ...metric cards grid (LlmCard + LlmBadge delta)... -->
<llm-table variant="striped" size="sm">
<llm-thead>
<llm-tr><llm-th>User</llm-th><llm-th>Action</llm-th></llm-tr>
</llm-thead>
<llm-tbody>
@for (row of activity(); track row.id) {
<llm-tr>
<llm-td>{{ row.user }}</llm-td>
<llm-td>{{ row.action }}</llm-td>
</llm-tr>
}
</llm-tbody>
</llm-table>
<llm-progress [value]="quota()" variant="warning" size="sm" />

Open in Storybook

The same composition with state, styles, and demo data — running live in each framework Storybook.