Data Table
interlace-ui/data-tableFreeComponent
Columns, sorting, row selection, pagination, and the three states a table spends most of its life in (loading / empty / error). It composes primitives — Checkbox, Pagination, Skeleton, Button — so it is a pattern, not a primitive.
Install it
npx shadcn@latest add https://ds.interlace.tools/r/data-table.jsonSource
1'use client';23import * as React from 'react';45// @interlace/data-table v1.0.0 — Interlace design system.6// Docs, props and live preview: https://ds.interlace.tools/c/data-table7// What changed since: https://ds.interlace.tools/c/data-table#history8// Generated banner — keep it, the upgrade diff reads this version.910/**11 * @interlace/ui — DataTable12 *13 * Columns, sorting, row selection, pagination, and the three states a table14 * spends most of its life in (loading / empty / error). It composes15 * primitives — Checkbox, Pagination, Skeleton, Button — so it is a pattern,16 * not a primitive.17 *18 * ## It is a real `<table>`19 *20 * Not a grid of divs. `<caption>` names it, `<th scope="col">` names each21 * column, and one column per row is a `<th scope="row">` that names the row22 * (`rowHeader` on the column, defaulting to the first). That triple is what23 * makes a screen reader announce "Revenue, March, 41,200" instead of24 * "41,200" — a bare number in a bare cell is unreadable by anyone not25 * looking at the screen, and no amount of `aria-label` on the wrapper fixes26 * it. It is the same contract `charts/series-table.tsx` exists to honour for27 * the chart layer.28 *29 * ## State is the caller's30 *31 * `sort` / `onSortChange` and `selected` / `onSelectionChange` are props, not32 * `useState`. The table renders `rows` in the order it received them and33 * highlights the keys it was handed.34 *35 * That is not purity for its own sake — it is the only shape that satisfies36 * URL_PHILOSOPHY / DEEP_LINKING_PHILOSOPHY. Table state belongs in the query37 * string (`?sort=createdAt&dir=desc&page=3`) so a filtered, sorted, paged38 * view survives a refresh and can be pasted to a colleague. A table holding39 * its own sort state cannot put it there, and the "controlled OR uncontrolled"40 * compromise is worse: it makes the URL an optional feature, which means it41 * is the feature nobody wires up. It also means the SORT ITSELF is the42 * caller's — server-side for anything real; `sortRows` from43 * `./data-table-model.js` for the small in-memory case.44 *45 * Selection is keyed by row ID (`rowKey`), never by index, so it survives46 * both sorting and pagination.47 *48 * ## MIN_VIEWPORT — 32049 *50 * The table scrolls horizontally inside its own container; the page never51 * does. The pager and the selection bar sit OUTSIDE that container, so they52 * stay put while the columns scroll under them.53 *54// … truncated
More from interlace-ui
All 140 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| A11y Startera11y-starter | interlace-ui | Components | Free | no deps | |
| Accordionaccordion | interlace-ui | Components | Free | no deps | |
| Alertalert | interlace-ui | Components | Free | no deps | |
| Alert Dialogalert-dialog | interlace-ui | Components | Free | no deps | |
| Animated Gradient Textanimated-gradient-text | interlace-ui | Components | Free | no deps | |
| Animated Grid Patternanimated-grid-pattern | interlace-ui | Components | Free | no deps | |
| Animated Listanimated-list | interlace-ui | Components | Free | no deps | |
| Article Cardarticle-card | interlace-ui | Components | Free | no deps |
