Skip to content
GetUrUI

Data table

NewPro
.md

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

PropTypeDefaultDescription
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 / toolbarReactNode—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.
selectablebooleanfalseAdds a checkbox column; the header box turns indeterminate on partial selection.
selected / defaultSelected / onSelectedChangestring[]—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.
stripedbooleanfalseAlternate row fills.
stickyHeader / maxHeightboolean / number | string—Pin the header inside a scrolling body.
status"ready" | "loading" | "error""ready"Loading shows shimmer skeleton rows; error shows a retry state.
filteredboolean—An empty result shows no-results (with onClearFilters) instead of the empty state.
emptyState / noResultsState / errorStateReactNode—Replace the built-in state blocks.
onRetry / onClearFilters() => void—Adds Try again and Clear filters buttons to the built-in states.
footerReactNode—Slot under the table for pagination or totals.
AvatarCell / BadgeCell / ProgressCell / TrendCellcomponents—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.

Related