Skip to content
quartiledocsv0.1
GitHub

DataTable

PreviewPublishes selection

Rows with typed cells (bars, sparklines, deltas, badges, status dots) that follow the selection, publish a field on click, sort, paginate and virtualize.

Example

Top products
Ranked by revenue. Change compares the later half of the period with the earlier half.
#Trend
1Field JacketKST-1042Apparel$132.3K30.8%+19.0%In stock
2Trail Runner 2KST-2210Footwear$55.5K12.9%+7.6%Low stock
3Hiking BootKST-2291Footwear$42.1K9.8%+28.4%In stock
4Wool ThrowKST-3307Home$39.0K9.1%+13.7%In stock
5Stoneware SetKST-3381Home$29.6K6.9%+0.2%Backorder
1–5 of 12 products · Select rows to publish to the selection
const columns: DataTableColumn[] = [
  { field: 'product', label: 'Product', secondary: 'sku' },
  { field: 'category', label: 'Category', cell: 'badge' },
  { key: 'revenue', field: 'amount', label: 'Revenue', aggregate: 'sum', format: 'currency-compact' },
  { key: 'share', field: 'amount', label: 'Share', aggregate: 'sum', cell: 'bar', share: true },
  { key: 'trend', field: 'amount', label: 'Trend', cell: 'sparkline', over: 'date' },
  { key: 'change', field: 'amount', label: 'Change', cell: 'delta', over: 'date' },
  { field: 'stock', label: 'Status', cell: 'status', tones: { 'In stock': 'positive', 'Low stock': 'warning', Backorder: 'negative' } },
];

<Selection>
  <DataTable
    data={orders}
    groupBy="product"
    columns={columns}
    select="product"
    rank
    defaultSort="-revenue"
    pageSize={5}
    noun="products"
    title="Top products"
    caption="Ranked by revenue. Change compares the later half of the period with the earlier half."
  />
</Selection>

Usage

Columns read field from each row. Give a column its own key when two columns read the same field, as Revenue and Share do above; this works with or without groupBy. Sort by key, with - for descending.

For a complete toolbar with search, typed filters, saved views, column controls and export, use DataExplorer. DataTable also supports ordered sorts, controlled page, pinned numeric-width columns and typed onCellEdit commits. Multi-sort takes precedence over the single-sort API; use manualSort when your data source supplies the ordering.

groupBy collapses rows to one per value and aggregates each column with aggregate; sparkline and delta cells use over to build a series per group. For other shapes, transform derives the displayed rows from the linked rows.

// Raw rows, no groupBy: two columns read "amount"
<DataTable
  data={orders}
  sort="-amount"
  limit={8}
  columns={[
    { field: 'product' },
    { field: 'amount', label: 'Revenue' },
    { key: 'amount_bar', field: 'amount', label: 'Size', cell: 'bar' },
  ]}
/>
Inside a <Selection> the table shows the rows that pass every predicate except its own. With select, clicking a row or pressing Enter toggles that row's value. Past 200 rows (virtualize) only the visible rows render, unless you paginate.

Props

DataTable

PropTypeDefaultDescription
datarequiredDataInput<R>—Rows, or a dataset with a schema. Filtered by the nearest Selection.
columnsrequiredDataTableColumn<Row>[]——
groupBystring—Collapses rows to one per value of this field; columns aggregate with aggregate.
transform(rows: R[]) => Row[]—Derives displayed rows from the linked rows (runs instead of groupBy).
sortstring | null—Column key to sort by; prefix with "-" for descending, e.g. "-revenue".
defaultSortstring——
onSortChange(sort: string | null) => void——
sortsreadonly SortState[]—Ordered multi-sort priorities. When supplied, takes precedence over the single sort prop.
defaultSortsreadonly SortState[]——
onSortsChange(sorts: SortState[]) => void——
manualSortbooleanfalseRows are already ordered by an external query. Headers still publish onSortChange.
typedSelectionbooleanfalsePreserve physical field identities for prepared query results (including nominal dates).
limitnumber—Keeps only the first N rows after sorting.
pageSizenumber—Paginates with Previous / Next in the footer.
pagenumber—Controlled zero-based page.
defaultPagenumber0—
onPageChange(page: number) => void——
rowKeystring | ((row: Row, index: number) => string)—Stable row identity: a field, or a function.
selectstring—Field published to the selection when a row is clicked or Enter is pressed; selected rows highlight with a check. The table is not filtered by its own selection.
multiplebooleantrueSelect several rows (default) or one.
rankbooleanfalseAdds a leading rank column (1, 2, 3 … after sorting).
titleReactNode——
captionReactNode—Secondary line under the title.
toolbarReactNode—Controls on the right of the title row.
footerReactNode—Right side of the footer.
nounstring'rows'Plural noun for the page label, e.g. "products" in "1–8 of 12 products".
virtualizenumber | false200Row count above which only the visible rows render inside a fixed-height scroller. Defaults to 200; false turns it off. Ignored when paginating.
heightnumber—Scroller height in px when virtualized (or to cap the table). Defaults to 480 when virtualized.
selectionstring | false—Selection to read from and publish to. Defaults to the nearest; false opts out.
idstring—Publisher id.
onRowClick(row: Row) => void——
onCellEdit(edit: DataTableEdit) => void | Promise<void>—Controlled write: update the caller's data after accepting this edit. Rejections remain visible.
classNamestring——
styleCSSProperties——
aria-labelstring——
Frame and state props shared with the charts (5) · ChartStateProps
PropTypeDefaultDescription
loadingboolean | string—Shows the loading state at the chart's size, so the layout never jumps.
errorboolean | string | Error | null—Shows the error state. A string or Error becomes the message.
errorCodestring—Shown in the error state; copyable for support.
onRetry() => void——
empty{ title?: string; description?: string; action?: ReactNode }—Title and description for the empty state. Shown when there are no rows.

DataTableColumn

PropTypeDefaultDescription
fieldrequiredstring—Field read from each row (or aggregated from each group with groupBy).
keystring—Unique column id; defaults to field. Set it when two columns read the same field.
labelReactNode—Header text. Defaults to the field's schema label.
descriptionstring—Field explanation shown on header hover/focus. Defaults to the schema description.
formatFormatter—Value format. Defaults to the field's schema format.
align'left' | 'center' | 'right'——
widthnumber | string—Grid track: a number (px) or any CSS track, e.g. "minmax(160px, 2fr)".
cellCellKind | ((row: R, index: number) => ReactNode)—How the value renders: text (with optional secondary line), number (mono, right), bar (in-cell bar scaled to the column max), sparkline (an array of numbers), delta (signed pill), badge (tag) or status (dot + text). Or a function returning any node.
sortableboolean—Click the header to sort. Defaults to true except for sparklines.
secondarystring—Text cells: a second mono line from this field, e.g. a SKU.
tonesRecord<string, Tone>—Badge and status cells: tone per value, e.g. { "In stock": "positive" }.
deltaKind'percent' | 'pt' | 'number'DeltaKind—Delta cells: ratio ("percent") or points ("pt").
deltaDigitsnumber—Delta decimal places, an integer from 0 to 20. Defaults to 1 for percent/number, 2 for pt.
invertboolean—Delta cells: down is good.
shareboolean—Bar cells: label shows the value's share of the column total instead of the value.
aggregate'sum' | 'count' | 'mean' | 'min' | 'max'AggregateName—With groupBy: how the field combines across a group.
overstring—With groupBy, for sparkline and delta cells: the series is the aggregate per distinct value of this field. A delta compares the later half of that series with the earlier half.
pinned'left' | 'right'—Keep this column visible while scrolling horizontally. Pinned columns use a fixed pixel track.
editableboolean | DataTableEditor—Editable only when onCellEdit and a stable rowKey are supplied, and rows are not grouped.

Typed editor

PropTypeDefaultDescription
type'text' | 'number' | 'date' | 'boolean' | 'select'—Defaults to the field's schema type. Dates edit a UTC calendar day as YYYY-MM-DD.
optionsreadonly { value: TableScalar; label: string }[]——
nullableboolean——
validate(value: TableScalar, row: Row) => string | null | undefined—Return an error message to keep the editor open without publishing an edit.

Edit commit

PropTypeDefaultDescription
rowrequiredRow——
rowKeyrequiredstring—Stable identity produced by the DataTable rowKey prop.
fieldrequiredstring——
columnKeyrequiredstring——
previousValuerequiredunknown——
valuerequiredTableScalar——

Accessibility

  • A table role, or grid when rows are interactive. Sortable headers are buttons and report aria-sort.
  • In an interactive table, ↑ ↓ move between rows, Home, End, Page Up and Page Down jump, and Enter selects. Selected rows report aria-selected.
  • Name the table with title or aria-label.
Report an issueBuilt Oct 21, 2026