DataTable

Organism

Unified table with `mode="static" | "paginated" | "server"`. Multi-column sort (Shift+click), global search, per-column filter (text + select), pagination, unified loading/empty/error state, and `rowActions` (a per-row actions menu with id, href, hidden, disabledReason, destructive, group and order).

Full example

Preview
Users
NameEmailRoleStatusJoined
Alice Martinalice@example.comAdminActive2024-01-15
Bob Johnsonbob@example.comMemberActive2024-02-20
Carol Williamscarol@example.comEditorInactive2024-03-10
David Browndavid@example.comMemberActive2024-04-05
Eve Daviseve@example.comAdminActive2024-05-18

Showing 1–5 of 8

Code
<DataTable
  caption="Users"
  searchPlaceholder="Search users…"
  pageSize={5}
  rows={users}
  columns={[
    { key: 'name',   header: 'Name' },
    { key: 'email',  header: 'Email' },
    { key: 'role',   header: 'Role' },
    { key: 'status', header: 'Status', render: (r) => <Badge variant={...}>{r.status}</Badge> },
    { key: 'joined', header: 'Joined' },
  ]}
/>

Sortable columns

Preview
Products
ProductCategoryPriceStock
Widget ATools29.99150
Gadget BElectronics99.0042
Part CTools9.50500
Device DElectronics249.0018
Item EMisc14.75200

Showing 1–5 of 5

Code
<DataTable
  rows={products}
  columns={[
    { key: 'name',  header: 'Product',  sortable: true },
    { key: 'price', header: 'Price',    sortable: true, align: 'right' },
  ]}
/>

Server mode (mode="server")

Preview
Server-paged users
NameEmailTeamJoined
Loading…Loading…

No results

Code
// Unified server-side data flow — the component owns sort/filter/pagination state
// and calls `fetchPage` whenever it changes.
<DataTable<User>
  mode="server"
  fetchPage={async ({ page, pageSize, sort, search, filters }) => {
    const res = await fetch(buildUrl({ page, pageSize, sort, search, filters }));
    const { rows, total } = await res.json();
    return { rows, total };
  }}
  pageSize={5}
  searchPlaceholder="Search users…"
  columns={[
    { key: 'name',  header: 'Name',  sortable: true },
    { key: 'email', header: 'Email', sortable: true, filter: { kind: 'text' } },
    { key: 'team',  header: 'Team',  sortable: true, filter: { kind: 'select', options: [
      { label: 'Platform', value: 'platform' },
      { label: 'Growth',   value: 'growth' },
    ] } },
  ]}
/>

Row actions (rowActions)

Preview
Companies
CompanyEmailStatusActions
Northwind Tradersbuy@northwind.exampleActive
Contoso Ltd—Active
Fabrikaminfo@fabrikam.exampleArchived

Nothing run yet

Code
// A trailing column with one menu per row. Every per-row field takes a function of the row.
<DataTable<Company>
  rows={companies}
  columns={columns}
  rowActionsLabel={(row) => `Actions for ${row.name}`}
  rowActions={[
    { id: 'open', label: 'Open', href: (row) => `/companies/${row.id}` },
    { id: 'call', label: 'Call', group: 'contact', order: 10, onClick: (row) => call(row) },
    { id: 'sign', label: 'Send for signature', group: 'contact', order: 20,
      disabled: (row) => !row.email, disabledReason: (row) => (row.email ? undefined : 'Add an email address first') },
    { id: 'restore', label: 'Restore', hidden: (row) => row.status !== 'Archived' },
    { id: 'delete', label: 'Delete', group: 'danger', order: 1000, destructive: true, onClick: remove },
  ]}
/>
Sourcemodules/ui/Table/DataTable.tsx