Data Tables & Dashboards
When to Use
Tabular or data-dense UI: data tables, lists, grids, pagination, sorting, filtering, row selection, KPI cards, charts, analytics dashboards, admin panels. Mentions of TanStack Table/Query route here.
Stack
React 19 · TypeScript strict · Tailwind v4 · TanStack Table/Query · Recharts (default)
Core Rules
- Semantic
<table> for tabular data. Never div-grids. Sortable headers use <th aria-sort> wrapping a <button>; the sort cycle is asc → desc → none.
- Selection. Leading checkbox column, header checkbox carries the
indeterminate state, bulk-action bar sits above the table and announces its count via aria-live="polite".
- Overflow is keyboard-reachable. Wrap in
overflow-x-auto with tabIndex={0}, role="region" and an aria-label.
- Default to pagination. Infinite scroll only for feeds where SEO is irrelevant, and always with a "Load more" button for keyboard users. Past ~100 rendered rows, virtualize.
- State lives in the URL. Filters, sort, page and expanded panels go in query params so views are shareable and restorable.
- Numbers are
tabular-nums and formatted with Intl.NumberFormat; dates with Intl.DateTimeFormat. Never hardcode formats.
- Charts need a text equivalent.
role="img" plus an aria-label stating the trend; a summary line beside the chart serves both sighted scanners and screen readers.
- Four states per data surface. Skeleton matching the final layout (no CLS), empty with a route out, error with
role="alert" and retry, success.
- Never colour alone for status — pair with icon or text.
Patterns
- TABLE-ROW = search/filter bar + table + pagination.
- METRIC-ROW = 4 KPI cards (value, label, trend with direction icon, optional sparkline).
- CHART-ROW = large chart (2/3) + summary panel (1/3), or two medium charts.
- Optimistic mutation — update the cache, roll back on error (see tanstack-query).
- DASH-LAYOUT = sidebar 240px + header 56px + flexible content.
Examples
examples/good-data-table.tsx (sort, select, paginate, all states) · examples/good-tanstack.tsx (useQuery/useMutation/useInfiniteQuery, optimistic) · examples/good-dashboard.tsx (KPI + charts).
Reference Index
Load only for the specific task:
| Task |
Load |
| Table/KPI/chart/feed pattern anatomy (P-09…P-12), pagination-vs-infinite matrix |
../landing-pages/references/design-patterns.md |
| 25 chart types with accessibility ratings |
references/chart-types.md |
| Queries, mutations, infinite scroll, SSR prefetch |
references/tanstack-query.md |
| URL state (nuqs), localStorage, cross-tab sync |
references/memory-persistence.md |
Constraints
Semantic table markup with aria-sort · keyboard-reachable overflow · tabular-nums and Intl.* formatting · four states with skeletons that don't shift layout · OKLCH tokens · TypeScript strict · WCAG 2.2 AA · no mount-time fake delays.
1---2name: data-tables3description: Tables, grids, charts and dashboards — sorting, filtering, pagination, selection, KPIs, data fetching. Use when the UI is tabular or data-dense — data tables, lists, grids, pagination, sorting, filtering, row selection, KPI cards, charts, analytics dashboards, admin panels. TanStack Table or Query route here.4---56# Data Tables & Dashboards78## When to Use9Tabular or data-dense UI: data tables, lists, grids, pagination, sorting, filtering, row selection, KPI cards, charts, analytics dashboards, admin panels. Mentions of TanStack Table/Query route here.1011## Stack12React 19 · TypeScript strict · Tailwind v4 · TanStack Table/Query · Recharts (default)1314## Core Rules151. **Semantic `<table>` for tabular data.** Never div-grids. Sortable headers use `<th aria-sort>` wrapping a `<button>`; the sort cycle is asc → desc → none.162. **Selection.** Leading checkbox column, header checkbox carries the `indeterminate` state, bulk-action bar sits above the table and announces its count via `aria-live="polite"`.173. **Overflow is keyboard-reachable.** Wrap in `overflow-x-auto` with `tabIndex={0}`, `role="region"` and an `aria-label`.184. **Default to pagination.** Infinite scroll only for feeds where SEO is irrelevant, and always with a "Load more" button for keyboard users. Past ~100 rendered rows, virtualize.195. **State lives in the URL.** Filters, sort, page and expanded panels go in query params so views are shareable and restorable.206. **Numbers are `tabular-nums`** and formatted with `Intl.NumberFormat`; dates with `Intl.DateTimeFormat`. Never hardcode formats.217. **Charts need a text equivalent.** `role="img"` plus an `aria-label` stating the trend; a summary line beside the chart serves both sighted scanners and screen readers.228. **Four states per data surface.** Skeleton matching the final layout (no CLS), empty with a route out, error with `role="alert"` and retry, success.239. **Never colour alone** for status — pair with icon or text.2425## Patterns26- **TABLE-ROW** = search/filter bar + table + pagination.27- **METRIC-ROW** = 4 KPI cards (value, label, trend with direction icon, optional sparkline).28- **CHART-ROW** = large chart (2/3) + summary panel (1/3), or two medium charts.29- **Optimistic mutation** — update the cache, roll back on error (see tanstack-query).30- **DASH-LAYOUT** = sidebar 240px + header 56px + flexible content.3132## Examples33`examples/good-data-table.tsx` (sort, select, paginate, all states) · `examples/good-tanstack.tsx` (useQuery/useMutation/useInfiniteQuery, optimistic) · `examples/good-dashboard.tsx` (KPI + charts).3435## Reference Index36Load only for the specific task:3738| Task | Load |39|---|---|40| Table/KPI/chart/feed pattern anatomy (P-09…P-12), pagination-vs-infinite matrix | `../landing-pages/references/design-patterns.md` |41| 25 chart types with accessibility ratings | `references/chart-types.md` |42| Queries, mutations, infinite scroll, SSR prefetch | `references/tanstack-query.md` |43| URL state (nuqs), localStorage, cross-tab sync | `references/memory-persistence.md` |4445## Constraints46Semantic table markup with `aria-sort` · keyboard-reachable overflow · `tabular-nums` and `Intl.*` formatting · four states with skeletons that don't shift layout · OKLCH tokens · TypeScript strict · WCAG 2.2 AA · no mount-time fake delays.