Data

DataTable

Records to sort, select and hide columns in, on TanStack Table v9, rendered as a real table. Sorting says its order to screen readers, every row's checkbox names the row, and past 500 rows only the rows in view are rendered. It carries its own states under the header: skeleton rows in the table's shape while loading, an EmptyState when there is nothing yet, another when the filters hide everything, with a button to clear them, and an error with a retry in place of rows that would read as current. Below 640px, show the same data as ListRows.

view .md
Preview
2026-09-27coffeeout−$4.50
2026-09-27bookslearning−$62.00
2026-09-26client invoiceincome+$9,500.00
2026-09-26renthome−$1,800.00
2026-09-25grocerieshome−$123.80
2026-09-25cinemaout−$32.00
2026-09-24refundincome+$89.90
Installation
terminal
bash
npx @entrepta/cli@latest add data-table

// Resolves dependencies, copies the source, and installs npm packages automatically.

Usage
data-table.tsx
tsx
import { DataTable, dataTableColumns } from "@/components/entrepta/data-table"

const col = dataTableColumns<Entry>()
const columns = col.columns([
  col.accessor("date", { header: "date" }),
  col.accessor("item", { header: "item" }),
  col.accessor("amount", {
    header: "amount",
    cell: (info) => <Amount value={info.getValue()} tone="auto" />,
  }),
])

<DataTable
  aria-label="entries"
  data={entries}
  columns={columns}
  getRowId={(entry) => entry.id}
  numeric={["amount"]}
  selectable
  rowLabel={(entry) => `Select ${entry.item}`}
  loading={isLoading}
  error={failed ? { description: failed.message, onRetry: refetch } : null}
  filtered={filters.length > 0}
  onClearFilters={clearFilters}
  empty={{ title: "No entries yet", action: <Button>add an entry</Button> }}
/>
Props
PropTypeDefaultDescription
data / columnsT[] / columns from dataTableColumns<T>()-The records, and the columns built with the typed helper
numericstring[]-Column ids aligned right in tabular figures
sorting / onSortingChange / manualSortingSortingState / OnChangeFn / boolean-Controlled sorting; manual when the server sorts
selectable / rowSelection / rowLabelboolean / RowSelectionState / (row) => string-A checkbox per row, named by rowLabel, and one for all
columnVisibilityColumnVisibilityState-Which columns show
loadingbooleanfalseSkeleton rows in the table's shape, numbers on the right
empty{ title?, description?, action?, icon? }-No rows yet: what is missing and the one thing to do
filtered / onClearFiltersboolean / () => void-The filters hide every row: says so and offers to clear them
error{ title?, description?, onRetry? } | null-The rows did not load: announced, with a retry, instead of the rows
labels{ emptyTitle?, filteredTitle?, clearFilters?, errorTitle?, retry?, … }-The words of the built-in states, for another language
maxHeightnumber-Scrolls in its box; required to virtualize more than 500 rows
Active theme: entrepta, dark mode.