registry
@automindzsheets 01–77shadcn 4.x
SHEET 12

Data Table

block / data / table

Sortable, searchable, paginated table with in-cell visualisations and every state, on real table semantics. No table engine, no chart library.

type
block
files
3
registry deps
avatar, badge, button, checkbox, input, skeleton, @automindz/empty-state
npm deps
lucide-react

installs

  • lib/automindz/table-model.ts
  • components/automindz/data-cells.tsx
  • components/automindz/data-table.tsx
  • Columns are a prop — add one without editing the table
  • In-cell bar, donut, sparkline, heat, target and distribution, all inline SVG
  • Hover any chart for detail; one tooltip for the whole table, never two

Columns are a prop: value(row) is the one sortable and searchable primitive, cell(row, context) draws it, and context.stats carries that column's max and total over the *filtered* rows — so a bar means the same thing on every page. rows={undefined} renders the skeleton, rows={[]} the empty state, and error the failure with a retry. The lib is table-model.ts, not data-table.ts, because shadcn add rewrites imports across the whole install by basename — do not rename it back. If you installed this item before the rename, delete the leftover lib/automindz/data-table.ts: it still exports the same contract and will silently go stale.

Variations

one state per section

01

Client accounts, everything live

Sort any header, search, page through. The client column is the row header (<th scope="row">); numeric columns are right-aligned with tabular figures; every visualisation prints its value beside the mark, so nothing is carried by colour or length alone. Sweep across a sparkline and the readout snaps to the nearest real point with a marker on it; the bar names the column maximum it is scaled against and the donut names the total it is a share of — both invisible on the mark. Only one bubble can exist at a time, however fast you sweep.

fluid
Client accounts, monthly spend and API usage
LRLumen RetailActive$15,300, 100% of the $15,300 column maximum
HHyreflowActive$12,780, 84% of the $15,300 column maximum
MHMeridian HealthActive$9,150, 60% of the $15,300 column maximum
SMSolstice MediaActive$8,470, 55% of the $15,300 column maximum
O&Orchard & CoActive$5,640, 37% of the $15,300 column maximum
NLNorthwind LabsActive$4,860, 32% of the $15,300 column maximum

Showing 1–6 of 14 rows

Page 1 of 3
02

In-cell visualisations

Heat cell (five binned steps of one hue), progress toward a target with the target marked by a tick rather than implied, and a channel breakdown whose sixth category folds into “Other” — there are five chart tokens, so a sixth colour is never invented. Hover any of the three: the heat cell names the band it landed in, the target bar gives the percentage attained, and the traffic mix names the segment under the pointer, including what “Other” swallowed. Every one of those strings is in the cell's sr-only text too, so the tooltip is a convenience and never the only route to a value.

fluid
Client accounts, usage intensity, seat headroom and traffic mix
Traffic mix, share of sessions by channel
HHyreflow512.9K, band 5 of 5: 410.3K to 512.9K48 / 60 seats, 80% of the targetOrganic 52%Organic 52%, Paid 18%, Referral 16%, Email 7%, Other 7% (Social, Direct)
MHMeridian Health288.7K, band 3 of 5: 205.2K to 307.7K34 / 60 seats, 57% of the targetOrganic 61%Organic 61%, Referral 13%, Email 11%, Paid 9%, Other 6% (Social, Direct)
BHBright Harbour141K, band 2 of 5: 102.6K to 205.2K19 / 20 seats, 95% of the targetOrganic 33%Organic 33%, Paid 27%, Referral 19%, Email 12%, Other 9% (Social, Direct)
NLNorthwind Labs128.4K, band 2 of 5: 102.6K to 205.2K17 / 20 seats, 85% of the targetOrganic 46%Organic 46%, Paid 22%, Referral 14%, Email 9%, Other 9% (Social, Direct)
CCastUK96.2K, band 1 of 5: 0 to 102.6K12 / 20 seats, 60% of the targetOrganic 38%Organic 38%, Paid 31%, Email 12%, Referral 11%, Other 8% (Social, Direct)
KLKestrel Logistics12.4K, band 1 of 5: 0 to 102.6K5 / 5 seats, 100% of the targetOrganic 41%Organic 41%, Referral 22%, Paid 19%, Email 9%, Other 9% (Social, Direct)
AFAtlas Freight8,100, band 1 of 5: 0 to 102.6K4 / 5 seats, 80% of the targetPaid 44%Paid 44%, Organic 29%, Email 10%, Referral 8%, Other 9% (Social, Direct)
03

Sorting

Each header cycles ascending → descending → unsorted, and writes aria-sort as it goes. Sort by spend: Fernwood Estates has no spend, and a missing value stays last in both directions — it is not a small number.

fluid
Client accounts, sortable by every column
AFAtlas FreightTrialing$490, 3% of the $15,300 column maximum
KLKestrel LogisticsActive$780, 5% of the $15,300 column maximum
BHBright HarbourPast due$4,120, 27% of the $15,300 column maximum
MHMeridian HealthActive$9,150, 60% of the $15,300 column maximum
HHyreflowActive$12,780, 84% of the $15,300 column maximum
LRLumen RetailActive$15,300, 100% of the $15,300 column maximum
FEFernwood EstatesCanceled—
04

Row selection and bulk actions

The header checkbox selects the current page and goes indeterminate on a partial selection. The bulk bar sits above the table rather than floating over the rows, and the checkbox is its own cell — never a control nested inside another.

fluid

2 selected

Client accounts with bulk actions
NLNorthwind LabsActive$4,860, 38% of the $12,780 column maximum
CCastUKActive$3,240, 25% of the $12,780 column maximum
HHyreflowActive$12,780, 100% of the $12,780 column maximum
AFAtlas FreightTrialing$490, 4% of the $12,780 column maximum
MHMeridian HealthActive$9,150, 72% of the $12,780 column maximum
BHBright HarbourPast due$4,120, 32% of the $12,780 column maximum
05

Pagination

Four rows a page. Bar lengths and donut shares are computed over the filtered rows, not the page, so a bar means the same thing on page 1 and page 4. Search while on page 3 and the page resets instead of showing an empty body.

fluid
Client accounts, four to a page
NLNorthwind LabsActive$4,860, 32% of the $15,300 column maximum
CCastUKActive$3,240, 21% of the $15,300 column maximum
HHyreflowActive$12,780, 84% of the $15,300 column maximum
AFAtlas FreightTrialing$490, 3% of the $15,300 column maximum

Showing 1–4 of 14 rows

Page 1 of 4
06

Compact density

density="compact" tightens the row box and drops the type a step. Same columns, same cells, ~35% more rows in the same height — which is the point of a table.

fluid
Client accounts, compact density
LRLumen RetailActive$15,300, 100% of the $15,300 column maximum
HHyreflowActive$12,780, 84% of the $15,300 column maximum
MHMeridian HealthActive$9,150, 60% of the $15,300 column maximum
SMSolstice MediaActive$8,470, 55% of the $15,300 column maximum
O&Orchard & CoActive$5,640, 37% of the $15,300 column maximum
NLNorthwind LabsActive$4,860, 32% of the $15,300 column maximum
BHBright HarbourPast due$4,120, 27% of the $15,300 column maximum
VSVantage StudiosActive$3,980, 26% of the $15,300 column maximum
CCastUKActive$3,240, 21% of the $15,300 column maximum
KLKestrel LogisticsActive$780, 5% of the $15,300 column maximum

Showing 1–10 of 14 rows

Page 1 of 2
07

Loading

rows={undefined} renders skeleton rows built from each column's skeleton shape — avatar, pill, chart, number — so the placeholder row is the height of the real one and nothing jumps when the data lands.

fluid
Client accounts, loading
08

Nothing created yet

rows={[]} with no query. Reuses @automindz/empty-state inside the table body, so the header stays put and the message is the first-run one: name the thing, give one action.

fluid
Client accounts, none created yet

No client accounts yet

Add a client to start tracking spend, seats and API usage.

09

No search results

A different message from “nothing exists”, because the fix is different: clear the search. Seeded with defaultQuery so the state is here on arrival.

fluid
Client accounts, no search results

No rows match “invoice”

Try a shorter query, or clear the search.

10

Failed to load

The failure outranks the skeleton — with an error there is nothing coming. Rendered with role="alert", the reason spelled out, and a retry that stays busy while it runs. Press it: this one succeeds.

fluid
Client accounts, failed to load
11

Long values, horizontal scroll

The renewal note truncates with the full string in title, and minWidth makes the table wider than the frame: it scrolls inside its own container and the page never scrolls sideways.

fluid
Client accounts with renewal notes
Traffic mix, share of sessions by channel
NLNorthwind LabsGrowth plan renews 14 Sep 2026 — billing contact [email protected]GrowthActive$4,860, 38% of the $12,780 column maximum17 / 20 seats, 85% of the targetOrganic 46%Organic 46%, Paid 22%, Referral 14%, Email 9%, Other 9% (Social, Direct)
CCastUKGrowth plan renews 02 Oct 2026 — billing contact [email protected]GrowthActive$3,240, 25% of the $12,780 column maximum12 / 20 seats, 60% of the targetOrganic 38%Organic 38%, Paid 31%, Email 12%, Referral 11%, Other 8% (Social, Direct)
HHyreflowScale plan renews 28 Aug 2026 — billing contact [email protected]ScaleActive$12,780, 100% of the $12,780 column maximum48 / 60 seats, 80% of the targetOrganic 52%Organic 52%, Paid 18%, Referral 16%, Email 7%, Other 7% (Social, Direct)
AFAtlas FreightStarter plan renews 31 Aug 2026 — billing contact [email protected]StarterTrialing$490, 4% of the $12,780 column maximum4 / 5 seats, 80% of the targetPaid 44%Paid 44%, Organic 29%, Email 10%, Referral 8%, Other 9% (Social, Direct)
MHMeridian HealthScale plan renews 19 Nov 2026 — billing contact [email protected]ScaleActive$9,150, 72% of the $12,780 column maximum34 / 60 seats, 57% of the targetOrganic 61%Organic 61%, Referral 13%, Email 11%, Paid 9%, Other 6% (Social, Direct)
BHBright HarbourGrowth plan renews 07 Sep 2026 — billing contact [email protected]GrowthPast due$4,120, 32% of the $12,780 column maximum19 / 20 seats, 95% of the targetOrganic 33%Organic 33%, Paid 27%, Referral 19%, Email 12%, Other 9% (Social, Direct)
12

Narrow container

Held at 360px to show the container query: hideBelow columns drop out on the table's own width, not the viewport's, so the same table works in a sidebar and full-bleed. The donut stays circular and the bars shorten instead of distorting.

fluid
Client accounts in a 360px container
HHyreflowActive$12,780, 100% of the $12,780 column maximum
MHMeridian HealthActive$9,150, 72% of the $12,780 column maximum
NLNorthwind LabsActive$4,860, 38% of the $12,780 column maximum
CCastUKActive$3,240, 25% of the $12,780 column maximum
AFAtlas FreightTrialing$490, 4% of the $12,780 column maximum