Dashboard UI skill for Claude Code

Every widget answers a question you can name. Claude designs dashboards from the questions users ask instead of the data that happens to exist. It picks the chart that fits each question, builds KPI cards with named comparison periods, right-aligns tabular numbers, keeps filters in the URL, and gives every widget its own loading, empty, error and stale state so one failed query never blanks the page.

  • namedashboard-ui
  • size183 lines · ≈2,150 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Designs data-dense dashboards and admin screens — layout by the questions users ask, KPI cards with honest deltas, chart-type selection, readable data tables, filter bars with URL state, number formatting, and per-widget loading, empty, error, and stale states. Use when building an analytics dashboard, admin panel, reporting page, or internal tool, or when a dashboard is cluttered, hard to scan, or full of charts nobody reads.

Try asking

  • Design an analytics dashboard for our subscription metrics
  • This admin dashboard is cluttered and nobody reads it. Redesign the layout
  • Make our orders table easier to scan and add filters that persist in the URL

Use it when

  • Building an analytics, reporting, or admin screen
  • A dashboard is cluttered or hard to scan
  • Choosing chart types for specific metrics
  • Designing dense data tables with filters and bulk actions

Skip it when

How to check the result

Each widget maps to a written question, realistic messy data renders cleanly, and blocking one API request produces an isolated error state with retry.

The common mistake it prevents

Coloring deltas by direction instead of meaning, so a rising churn rate shows up in reassuring green.

~/.claude/skills/dashboard-ui/SKILL.md

--- name: dashboard-ui description: Designs data-dense dashboards and admin screens — layout by the questions users ask, KPI cards with honest deltas, chart-type selection,… license: MIT ---

A dashboard is done when each widget answers a named question, the most important number is the most prominent thing on screen, every number shows its unit, period, and comparison, tables scan in a single eye movement per column, and each widget handles loading, empty, error, and stale data on its own.

Ground rules

  • Start from questions, not from available data. “Are signups on track this month?” produces a better widget than “signups table”.
  • Chrome is neutral; color is reserved for data and status. A dashboard with a colored sidebar, colored cards, and colored charts has no signal left.
  • One primary chart type per question. Decoration (3D, gradients in bars, donut thickness tricks) is noise.
  • Filters and date ranges live in the URL so views are shareable and survive reload.
  • Density is a feature for expert users: favor 13–14px UI text, 32–40px table rows, and tight but consistent spacing over marketing-style whitespace.

Avoid the generic look

Default reflexBetter
Four identical KPI cards with icons in colored circlesKPI row with the hero metric larger; drop icons, show delta and sparkline instead
Every widget in a card with shadowFlat panels separated by 1px borders or background steps; cards only where grouping is unclear
Rainbow pie/donut chartsHorizontal bar sorted by value; donut only for 2–3 parts of a whole
Gradient-filled area chartsThin line (1.5–2px) plus light fill at 8–12% opacity, or no fill
Sidebar with 20 top-level items≤ 7 primary sections; the rest in grouped secondary nav or settings
“Welcome back, John!” banner eating the first 120pxPut the answer to the top question there

Workflow

- [ ] 1. List users, their top 3–5 questions, and the decision each one drives
- [ ] 2. Map each question to a widget type
- [ ] 3. Lay out by priority: hero metrics → trends → breakdowns → detail tables
- [ ] 4. Build filter bar and URL state
- [ ] 5. Specify every widget's states
- [ ] 6. Format numbers, dates, units consistently
- [ ] 7. Verify with real (or realistic, ugly) data

2. Widget selection

Question shapeWidget
“How much right now / vs. target?”KPI card: value, delta vs. comparable period, optional sparkline or progress to target
“How is it changing over time?”Line chart (continuous), column chart (≤ ~20 discrete periods)
“Which category is biggest?”Horizontal bar, sorted descending, direct labels
“What share of the whole?”Stacked bar (100%) or donut with ≤ 3 segments; never a pie with 8 slices
“How is it distributed?”Histogram or box plot
“Is there a relationship?”Scatter plot
“Where are the hotspots across two dimensions?”Heatmap with a sequential single-hue scale
“Which exact records?”Table with sort, filter, and row actions
“Did a flow leak?”Funnel as horizontal bars with step conversion %

3. Layout

  • 12-column grid, 16–24px gaps. Hero KPIs top-left (first eye fixation), 3–5 KPIs max in the top row.
  • Trend charts span 6–8 columns; breakdowns 4–6; tables full width.
  • Keep the most-used filter controls in a single sticky bar under the page header.
  • Page title + last-updated timestamp + date range visible without scrolling.

KPI card anatomy

Revenue (MTD)                      ← label, 13px, muted
$184,230                           ← value, 28–36px, tabular-nums, weight 600
▲ 12.4% vs. same period last month ← delta: arrow + sign + %, period named
[sparkline, 30 days]               ← optional, no axes, 32–40px tall
  • Delta color follows meaning, not direction: a rise in churn is red. Encode the arrow too (color is never the only signal).
  • Compare like with like: month-to-date vs. the same days last month, not vs. the full previous month.
  • Show ”—” with a tooltip when a comparison is unavailable, never “0%” or “NaN%”.

Chart rules

  • Bar/column axes start at zero. Line charts may start elsewhere if labeled clearly.
  • ≤ 5–7 series per chart; highlight one, gray the rest when comparing.
  • Direct labels beat legends; if a legend is needed, order it like the data.
  • No dual y-axes; use two aligned small charts instead.
  • Gridlines light (neutral at low contrast), 3–5 horizontal lines; no vertical gridlines for time series.
  • Categorical palette: 6–8 hues of similar lightness (OKLCH L ≈ 0.6–0.7 on light, 0.7–0.8 on dark) so no series dominates; sequential scales use one hue varying L.
  • Tooltips show the exact value, unit, and date; they are a supplement, not the only way to read values (provide a table view for accessibility).

Tables

RuleValue
Row height32px compact, 40px default, 48px comfortable (offer a density toggle)
NumbersRight-aligned, font-variant-numeric: tabular-nums, same decimals per column
TextLeft-aligned; truncate with ellipsis + full value in title/tooltip
HeaderSticky, sortable columns show sort direction, 12–13px weight 600
Zebra stripingOptional; prefer 1px row dividers; striping helps on very wide tables
Row actionsVisible on hover and on focus, plus an always-visible overflow menu for touch
Large dataPaginate (25/50/100) or virtualize beyond ~200 rendered rows
SelectionCheckbox column + bulk action bar that appears on selection

4. Filters and URL state

// Read and write filters through the URL so views are shareable
const params = new URLSearchParams(location.search);
params.set("range", "last_30d");
params.set("region", "emea");
history.replaceState(null, "", `?${params}`);
  • Date range presets first (Today, 7d, 30d, MTD, QTD, Custom); show the resolved dates and the timezone.
  • Show active filters as removable chips plus a “Clear all”.
  • Apply instantly for cheap queries; use an explicit Apply button when queries are slow.

5. Widget states (each widget independently)

StateDesign
LoadingSkeleton with the widget’s real shape; no full-page spinner
EmptySay why (“No orders in this range”) and offer the fix (widen range, clear filter)
ErrorInline in the widget: what failed + Retry; the rest of the dashboard stays usable
Partial / sampledBadge: “Sampled 10%” or “Incomplete: today’s data still processing”
Stale“Updated 3h ago” in muted text; warning color if beyond the SLA
No permissionExplain and name who can grant access

See empty-error-states for copy and patterns.

6. Formatting

const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0 });
const compact = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 }); // 1.2M
const pct = new Intl.NumberFormat("en-US", { style: "percent", maximumFractionDigits: 1 });
  • Compact notation in KPI cards and axes; full precision in tables and tooltips.
  • Always show units; label currencies when more than one exists.
  • Dates: relative for recent events (“5 min ago”), absolute with timezone on hover.

Gotchas

  • Averages of averages and percentages summed across segments mislead; compute from raw numerators and denominators.
  • Auto-refresh that re-renders charts every few seconds resets hover and scroll; refresh data in place and keep interaction state.
  • Truncated y-axes on bar charts exaggerate differences; reviewers notice.
  • Empty dashboards for new accounts are the first impression; design them with sample data or setup steps.
  • Timezone mismatches between server aggregation and the browser shift daily totals; state the timezone used for bucketing.

Verification

  • Load with production-like data volumes, including long names, zeroes, nulls, negative values, and 10× the expected row count.
  • For each widget, name its question; delete widgets that have no question.
  • Simulate slow and failed API responses per widget (DevTools request blocking) and confirm isolated error states.
  • Check keyboard access to sorting, filters, and row actions; charts have a data table alternative.
  • Grayscale screenshot: status and deltas still distinguishable via arrows/labels.

Output contract

## Dashboard spec: <name>
| Question | Widget | Metric definition | Comparison | Owner |
Layout: KPI row (Revenue MTD, Active accounts, Churn %), trend (8 col), breakdown (4 col), table
Filters (URL params): range, region, plan
States: specified per widget (loading / empty / error / stale)

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc