Typed table with sorting, row selection and loading, empty, no-results and error states; rows glide to their new order on sort and a bulk-action bar springs up as you select.
tabledata gridsortselectionbulk actionsskeletonempty statedashboard
Installation
Pro installs use your private registry token. Add the @geturui-pro registry once — setup guide. The command works after you get Pro.
$npx shadcn@latest add @geturui-pro/data-table
Also installs: Checkbox, Animated Badge, Button
Usage
usage.tsx
1import { AvatarCell, BadgeCell, DataTable, type DataTableColumn } from "@/components/ui/data-table";
2
3type Member = { id: string; name: string; email: string; status: "Active" | "Invited"; installs: number };
4
5const columns: DataTableColumn<Member>[] = [
6 { id: "name", header: "Member", rowHeader: true, sortable: true, accessor: (m) => m.name, cell: (m) => <AvatarCell name={m.name} description={m.email} /> },
7 { id: "status", header: "Status", cell: (m) => <BadgeCell tone={m.status === "Active" ? "success" : "info"}>{m.status}</BadgeCell> },
8 { id: "installs", header: "Installs", sortable: true, align: "end", accessor: (m) => m.installs, hideBelow: "sm" },
9];
10
11export function Members({ members }: { members: Member[] }) {
12 return (
13 <DataTable
14 caption="Workspace members"
15 title="Team members"
16 data={members}
17 columns={columns}
18 getRowId={(m) => m.id}
19 getRowLabel={(m) => m.name}
20 selectable
21 bulkActions={(ids, clear) => <button onClick={clear}>Remove {ids.length}</button>}
22 />
23 );
24}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
data* | T[] | — | Rows to show, already filtered. |
columns* | DataTableColumn<T>[] | — | id, header, accessor, cell, sortable, sortFn, align, width, hideBelow (sm–2xl), rowHeader, className. |
getRowId* | (row: T) => string | — | Stable id per row; keys the reorder animation and selection. |
caption* | string | — | Screen reader caption. The current sort is appended automatically. |
getRowLabel | (row: T) => string | — | Name used in each row checkbox label. |
title / description / count / toolbar | ReactNode | — | Optional card header with a count badge and a right-hand slot for search, filters or buttons. |
sort / defaultSort / onSortChange | { columnId, direction } | null | — | Sort state. Headers cycle ascending, descending, off. |
selectable | boolean | false | Adds a checkbox column; the header box turns indeterminate on partial selection. |
selected / defaultSelected / onSelectedChange | string[] | — | Selected row ids. |
bulkActions | (ids, clear) => ReactNode | — | Contents of the floating bar shown while rows are selected. |
rowActions | (row: T) => ReactNode | — | Trailing cell per row; bring your own buttons or menu. |
density | "compact" | "comfortable" | "comfortable" | Row height and cell padding. |
striped | boolean | false | Alternate row fills. |
stickyHeader / maxHeight | boolean / number | string | — | Pin the header inside a scrolling body. |
status | "ready" | "loading" | "error" | "ready" | Loading shows shimmer skeleton rows; error shows a retry state. |
filtered | boolean | — | An empty result shows no-results (with onClearFilters) instead of the empty state. |
emptyState / noResultsState / errorState | ReactNode | — | Replace the built-in state blocks. |
onRetry / onClearFilters | () => void | — | Adds Try again and Clear filters buttons to the built-in states. |
footer | ReactNode | — | Slot under the table for pagination or totals. |
AvatarCell / BadgeCell / ProgressCell / TrendCell | components | — | Cell helpers: initials avatar with two lines, status badge with dot, inline progress bar, signed trend with arrow. |
Accessibility
- A real <table> with a screen-reader caption; the name column renders th scope="row".
- Sortable headers are buttons and the sorted column carries aria-sort; the caption states the current sort.
- Row checkboxes are named "Select {row}"; the select-all box reports mixed when partially checked.
- The scroll region is focusable and labelled so keyboard users can scroll wide tables.
- Trend and status cells carry words, not colour alone. Row reorder, bar and shimmer animations are dropped under reduced motion.