Skip to content

API reference

The full DataTable surface: props, the twelve two-way model slices, change events, the imperative handle, and the slots. For the <Column> attribute reference see Columns; for the per-framework consumption code see the usage page.

Props

The full prop surface. The twelve model: true slices (the Two-way column — data plus the eleven state slices) are each an independent, optional two-way r-model with an uncontrolled fallback; with multiple model props the Angular output emits no ControlValueAccessor (the multi-model condition disables it — the per-prop valueChange outputs still drive each two-way binding).

NameTypeDefaultTwo-way (model)RequiredDescription
dataArrayThe row data — model: true, so a committed cell/row edit writes a fresh array back through r-model:data (uncontrolled fallback dataDefault). A stable reference per Rozie's setup-once model — fed directly into table-core (never map/cloned in the watcher).
columnsArray[]Config-array column fallback (lower precedence than <Column> children). Each entry: { id?, field, header?, sortable?, filterable?, pinned?, width? }. Columns may come from this array, from <Column> children, or both (id-keyed last-write-wins union).
selectionModeString"none"Row-selection mode: 'none' | 'single' | 'multiple'. 'multiple' auto-injects a leading checkbox column with a select-all header.
sortingArray[]SortingState[{ id, desc }]. Uncontrolled fallback when unbound. Two-way: writes funnel a fresh value through the sort-change event regardless of binding.
globalFilterString''The global search string — narrows all columns. Feeds getFilteredRowModel(). Surfaces through filter-change. Two-way: fires filter-change regardless of binding.
columnFiltersArray[]ColumnFiltersState[{ id, value }] per-column narrowing (gated by each column's filterable). Two-way: whole-array replace on write, fires filter-change.
paginationObject{…}{ pageIndex, pageSize }. Defaults to { pageIndex: 0, pageSize: 10 }; feeds the prev/next + page-size chrome (and getPaginationRowModel()). Two-way: funnels a fresh object through page-change.
manualBooleanfalseServer-side hook: sets manualPagination / manualFiltering / manualSorting so table-core trusts the consumer-supplied rows and only emits the change events (the consumer fetches each page).
expandableBooleanfalseOpt-in expandable rows. When true, a leading chevron expander column auto-injects (after the select column) and getExpandedRowModel activates; default false is byte-identical-off. Every row can expand to reveal a #detail panel unless getSubRows is supplied (then only rows with children expand). Bind :expandable="true" (a bare attr only coerces on Vue+Lit).
expandedanynullExpandedState{ [rowId]: true }, or the true literal after expandAll (declared type: [Object, Boolean]). Multi-expand (multiple rows open at once). Surfaces through expand-change; uncontrolled fallback ($data.expandedDefault) when unbound — the default is null so the uncontrolled fallback AND the grouping auto-expand default are reachable (a non-null default would short-circuit them). When grouping is active and expanded is untouched, group subtrees auto-expand.
getSubRowsFunctionnullTable-level child-row accessor (originalRow, index) => TData[] | undefined that drives nested sub-rows. When supplied (with expandable), table-core flattens the hierarchy and the expand seam reveals depth-indented child rows. Null → the #detail scoped slot is the expand mode.
groupableBooleanfalseOpt-in gate for the headless #groupBar host region. Default false is byte-identical-off. getGroupedRowModel is wired unconditionally (inert when grouping is empty), so grouping is driven by the grouping model; this flag only gates the consumer-facing group-bar surface (the component ships no built-in drag UI).
groupingArraynullGroupingState — an ordered string[] of column ids (multi-column → nested groups, e.g. ['region','category']). An empty/unbound list is ungrouped (byte-identical-off). Group-header rows are collapsible (they ride the expand model). Surfaces through group-change; uncontrolled fallback ($data.groupingDefault, default []) when unbound — the default is null (mirroring expanded) so the uncontrolled fallback is reachable and the grouping auto-expand default can activate when a consumer applies grouping without binding r-model:grouping (a non-null [] default would short-circuit it). All reads are null-guarded, so table-core still receives an array.
rowSelectionObject{}RowSelectionState{ [rowId]: true }. Checkbox-only toggle (the row body does not select). Driven by the selectionMode chrome. Two-way: fires selection-change regardless of binding.
columnVisibilityObject{}VisibilityState{ [colId]: boolean }. Hidden columns drop automatically from header + body. Two-way: funnels a fresh object through visibility-change.
columnSizingObject{}ColumnSizingState{ [colId]: number }. Driven live by the pointer-drag resize handle (columnResizeMode: 'onChange'). Two-way: fires resize-change.
columnOrderArray[]ColumnOrderStatestring[]. A fresh order array on reorder (never an in-place splice). Two-way: fires reorder-change.
columnPinningObject{…}ColumnPinningState{ left: string[], right: string[] }. Pinned columns get position: sticky + computed offsets. Defaults to { left: [], right: [] }. Two-way: fires pin-change.
stickyHeaderBooleanfalsePure-CSS sticky header: the <thead> sticks to the top of the scroll container.
interactionModeString"table"(deprecated) Reserved forward-compat seam — grid cell-navigation is not implemented yet; do not rely on the grid mode. 'table' (default, row-oriented) | 'grid'. 'grid' lights up the full WAI-ARIA grid interaction moderole="grid", a roving single tab-stop, and 2-D APG arrow-key cell navigation. 'table' is byte-behaviorally identical to a plain accessible table.
virtualBooleanfalseOpt-in vertical row windowing. When true, only the visible slice of rows renders inside a bounded rdt-scroll container (with leading/trailing spacer rows preserving total scroll height), windowing over the full filtered + sorted (pre-pagination) model and suppressing the client pagination chrome. Default false is byte-identical to a non-virtual table.
estimateRowHeightNumber40Estimated row height (px) seeding the windowing engine before measureElement refines actual heights. Only consulted when virtual is on.
maxHeightString''A CSS length string bounding the rdt-scroll container when virtual is on (e.g. '400px'). Mirrored to the --rozie-data-table-max-height custom property; the prop wins, the token is the fallback.

For the per-column <Column> attributes (field / header / sortable / filterable / pinned / width / groupable / aggregationFn / editable / editor / editorOptions / validate), see the Columns reference.

Models (the twelve two-way slices)

Each slice is an independent, optional two-way r-model with its own uncontrolled fallback and its own change event (which fires regardless of whether the slice is bound). All twelve state transitions are funneled through table-core; the table always writes a fresh value (never an in-place mutation, which would be silently dropped on React/Solid/Angular/Lit). The first slice is data itself — a committed cell or row edit writes a fresh data array back; the remaining eleven are the table-state slices.

Model (r-model:)ShapeChange eventDescription
dataTData[]data-changeThe row data. Two-way so committed cell/row edits flow back (uncontrolled fallback dataDefault). Always written as a fresh array, never mutated in place.
sorting[{ id, desc }]sort-changeThe sort state (header click; shift-click adds a secondary sort).
globalFilterstringfilter-changeThe global search string — narrows all columns.
columnFilters[{ id, value }]filter-changePer-column filter values (gated by each column's filterable).
pagination{ pageIndex, pageSize }page-changeThe current page index + size.
rowSelection{ [rowId]: true }selection-changeThe selected-row set (checkbox-only).
expanded{ [rowId]: true } | trueexpand-changeThe expanded-row set (multi-expand; the true literal = all rows expanded).
groupingstring[]group-changeThe ordered grouping key list (multi-column → nested groups). [] is ungrouped.
columnVisibility{ [colId]: boolean }visibility-changePer-column shown/hidden state.
columnSizing{ [colId]: number }resize-changePer-column widths (live during a resize drag).
columnOrderstring[]reorder-changeThe full column order.
columnPinning{ left: string[], right: string[] }pin-changePer-side pinned-column ids.

Events

Every change event fires regardless of whether the matching r-model slice is bound (the uncontrolled-fallback contract), so you can observe transitions without two-way binding. The payload is the fresh slice value (filter-change carries { globalFilter } or { columnFilters } depending on which filter changed).

EventDescription
sort-changeFired when the sort state changes (header click / shift-click multi-sort / a sortColumn/clearSorting call). Payload: the fresh SortingState [{ id, desc }].
filter-changeFired when a filter changes. Payload { globalFilter } for the global search box or { columnFilters } for a per-column filter — both surface through this one event.
page-changeFired when pagination changes (prev/next, a page-size change, or a setPage/setRowsPerPage call). Payload: the fresh { pageIndex, pageSize }.
selection-changeFired when the row selection changes (a row/select-all checkbox toggle or a toggleAllRows/clearSelection call). Payload: the fresh RowSelectionState.
expand-changeFired when the expanded-row set changes (an expander chevron toggle — click / Enter / Space — or a toggleRowExpanded/expandAll/collapseAll call). Fires exactly once per change. Payload: the fresh ExpandedState ({ [rowId]: true }, or the true literal after expandAll — pass through verbatim, never Object.keys without a === true guard). Named expand-change (not expanded-change) so it does not collide with the expanded model's onExpandedChange callback on the React/Solid Props interface.
group-changeFired when the grouping changes (a #groupBar apply/clear, mutating the grouping model, or an applyGrouping/clearGrouping call). Fires exactly once per change. Payload: the fresh GroupingState — an ordered string[] of column ids, or [] when cleared. Named group-change (not grouping-change) so it does not collide with the grouping model's onGroupingChange callback on the React/Solid Props interface.
visibility-changeFired when a column is shown/hidden (the column-toggle menu or a toggleColumnVisibility call). Payload: the fresh VisibilityState.
resize-changeFired live during a column resize drag (columnResizeMode: 'onChange'). Payload: the fresh ColumnSizingState.
reorder-changeFired when the column order changes (an applyColumnOrder call or a header reorder). Payload: the fresh ColumnOrderState.
pin-changeFired when a column is pinned/unpinned (the per-header pin buttons or a pinColumn call). Payload: the fresh ColumnPinningState.
activecell-changeGrid mode only. Fired when the active cell moves (arrow-key navigation, a click-to-activate, or a focusCell call) — but not on a clamped no-op edge move. Payload: { rowIndex, colIndex } (integer position over the visible model). See Grid interaction mode.
cell-edit-commitFired when an editable cell commits a new, validated value (Enter, a blur-commit, or a commitEditing call). Payload: { rowId, columnId, oldValue, newValue }. Not fired on cancel (Escape) or a validation failure. See Editing.
row-edit-commitFired when a full-row edit commits all its changes at once (Enter in row-edit mode or an editRow save). Payload: { rowId, changes } where changes is [{ columnId, oldValue, newValue }] for the columns whose value actually changed. Not fired on Escape or a validation failure.
range-changeGrid mode only. Fired when the rectangular cell-range selection changes (extended via Shift+Arrow / Shift+Click). Payload: { anchor, focus } — each corner a { rowIndex, colIndex } index pair over the visible model, or { anchor: null, focus: null } when no range is set. One-way (this event + the getSelectedRange verb), never a model:true slice.

Imperative handle

Declared once in the source via $expose; obtained through each framework's native ref mechanism. Each verb drives @tanstack/table-core so the matching change event fires.

MethodDescription
sortColumnToggle (or set) the sort for a column — sortColumn(colId, desc?). Fires sort-change.
clearSortingClear all sorting — clearSorting(). Resets to the unsorted core row model. Fires sort-change.
getColumnDefsReturn the resolved ColumnDef[] (the id-keyed LWW union of the :columns array and the <Column> children).
toggleAllRowsSelect or clear all (filtered) rows — toggleAllRows(value). Fires selection-change.
clearSelectionClear the row selection — clearSelection(). Fires selection-change with {}.
getSelectedRowsReturn the original row data for the selected rows — getSelectedRows()unknown[].
toggleRowExpandedToggle one row's expanded state — toggleRowExpanded(rowId) (the data id field or the table-core row id; both resolve). Multi-expand (does not collapse other rows). Fires expand-change.
expandAllOpen every expandable row — expandAll(). Fires expand-change (payload may be the true literal).
collapseAllCollapse every row — collapseAll(). Resets the expanded set to {}. Fires expand-change.
getExpandedRowsReturn the original row data for the currently-expanded rows — getExpandedRows()unknown[] (empty when nothing is expanded).
applyGroupingSet the full grouping — applyGrouping(cols) where cols is an ordered string[] of column ids (multi-column → nested groups). Fires group-change. (Named applyGrouping, not setGrouping, to avoid colliding with React's auto-generated grouping model setter — ROZ524.)
clearGroupingClear all grouping — clearGrouping(). Resets to the ungrouped (flat) row model. Fires group-change with [].
setPageGo to a 0-based page index — setPage(idx). Fires page-change.
setRowsPerPageSet the page size — setRowsPerPage(size). Fires page-change.
toggleColumnVisibilityShow/hide a column — toggleColumnVisibility(colId). Fires visibility-change.
applyColumnOrderSet the full column order — applyColumnOrder(order). Fires reorder-change. (Named applyColumnOrder, not setColumnOrder, to avoid colliding with React's auto-generated columnOrder model setter — ROZ524.)
resetColumnSizingReset all column widths to their defaults — resetColumnSizing(). Fires resize-change.
pinColumnPin a column to a side or unpin it — pinColumn(colId, side) where side is 'left' | 'right' | false. Fires pin-change.
getFacetedUniqueValuesReturn a column's cross-filtered distinct values — getFacetedUniqueValues(colId)unknown[] (keys only; occurrence counts are not exposed). Reflects rows passing all other active column filters. Empty array when unavailable. Inert (the faceted models stay off-path) until this verb or the #filter slot reads a facet. See Faceted filtering.
getFacetedMinMaxValuesReturn a numeric column's cross-filtered [min, max] range — getFacetedMinMaxValues(colId)[number, number] | null. null when unavailable or non-numeric. The read twin handed to the #filter slot for a numeric range slider.
editCellEditing. Open the editor on a cell — editCell(rowIndex, colIndex) (index-addressed over the visible model; args coerced to integers + clamped). No-op on a non-editable cell.
commitEditingEditing. Commit the open editor — commitEditing(). Runs the column validator; on success writes r-model:data and fires one cell-edit-commit; on a validation failure keeps the editor open. No-op when no cell is editing.
editRowEditing. Enter full-row edit on a body row — editRow(rowIndex) (the API twin of Shift+F2): every editable cell in the row opens at once; a later save commits the whole row in one r-model:data write + one row-edit-commit. No-op on a row with no editable columns.
getSelectedRangeReturn the current rectangular cell-range selection — getSelectedRange(){ anchor, focus } (each corner a { rowIndex, colIndex } index pair, or { anchor: null, focus: null }). One-way (this verb + range-change), never a model:true slice.
focusCellGrid mode. Move + DOM-focus the active cell by index — focusCell(rowIndex, colIndex) (coerced to integers and clamped to the visible model). Fires activecell-change.
getActiveCellGrid mode. Return the current active-cell position — getActiveCell(){ rowIndex, colIndex } (integers only; never a row object or DOM node).
clearActiveCellGrid mode. Reset the roving position to the entry cell (0,0) and exit interaction mode — clearActiveCell(). Does not emit (a reset, not a navigation).

Slots

All slots live on the parent <DataTable> (a <Column> carries metadata only). The cell / colHeader slots are single renderers dispatched by columnId. On React/Solid these are render-prop props (renderCell / renderColHeader / cellSlot / colHeaderSlot) and on Lit the .cell / .colHeader properties — the one documented cross-framework divergence.

SlotParamsDescription
cellcolumnId, column, row, valueCustom cell renderer — switch on columnId to vary per column. A column it does not render shows the plain accessor value.
colHeadercolumnId, column, labelCustom header renderer — switch on columnId. Falls back to the plain header label.
selectAllchecked, indeterminate, toggleOverride the select-all header (only when selectionMode="multiple"). indeterminate is true on a partial selection.
selectCellrow, checked, toggleOverride the per-row select checkbox (only when selectionMode="multiple").
detailrowCustom expanded-row content rendered under an expanded row (only when expandable and no getSubRows). The React render-prop edge (documented divergence).
groupBargrouping, groupableColumns, applyGrouping, clearGroupingHeadless group-bar (only when groupable). Receives the ordered grouping array, the groupableColumns ([{ id, label }]), and the applyGrouping/clearGrouping helpers so a consumer builds any bar/drag UI. The default render is a non-interactive styled-token reflection (empty when ungrouped); the component ships no drag affordance. The React render-prop edge (documented divergence).
filtercolumnId, uniqueValues, minMax, setFilterHeadless faceted-filter UI (only when a column is filterable). uniqueValues is the cross-filtered distinct values (unknown[], keys only); minMax is the cross-filtered numeric [min, max] (or null); setFilter(columnId, value) applies a column filter through the same funnel the built-in input uses (value of null/'' clears it). Build a checkbox list / range slider and call setFilter (or drive columnFilters directly) — the slot fires no event. See Faceted filtering. The React render-prop edge (documented divergence). Pair it with the drop-in filter components.
editorcolumnId, column, row, value, commit, cancelCustom cell editor (a column with editor="custom", or to override the built-in editor). value is the current draft; commit(newValue) validates + commits (fires cell-edit-commit); cancel() closes without saving; column/row are opaque passthroughs. Pair it with the drop-in editor components. The React render-prop edge (documented divergence).

See also

  • Columns — the <Column> attribute reference and cell/header rendering.
  • Theming — the --rozie-data-table-* token vocabulary.
  • Per-framework usage code — the idiomatic consumption snippet per target.

Pre-v1.0 — internal monorepo.