Appearance
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).
| Name | Type | Default | Two-way (model) | Required | Description |
|---|---|---|---|---|---|
data | Array | — | ✓ | ✓ | The row data — model: true, so a committed cell/row edit writes a fresh array back through the two-way data binding (uncontrolled fallback dataDefault). A stable reference per Rozie's setup-once model — fed directly into table-core (never map/cloned in the watcher). |
columns | Array | [] | 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). A pinned value of 'left' or 'right' is applied once as the table's initial columnPinning state — identical to <Column pinned> — which also REORDERS that column, since table-core orders visible cells [left-pinned, center, right-pinned]. A consumer who has already expressed a pin (an initial two-way columnPinning model value or an interactive pin) owns the slice and this declaration is ignored. | ||
selectionMode | String | "none" | Row-selection mode: 'none' | 'single' | 'multiple'. 'multiple' auto-injects a leading checkbox column with a select-all header. | ||
sorting | Array | [] | ✓ | SortingState — [{ id, desc }]. Uncontrolled fallback when unbound. Two-way: writes funnel a fresh value through the sort-change event regardless of binding. | |
globalFilter | String | '' | ✓ | The global search string — narrows all columns. Feeds getFilteredRowModel(). Surfaces through filter-change. Two-way: fires filter-change regardless of binding. | |
columnFilters | Array | [] | ✓ | ColumnFiltersState — [{ id, value }] per-column narrowing (gated by each column's filterable). Two-way: whole-array replace on write, fires filter-change. | |
pagination | Object | {…} | ✓ | { 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. | |
manual | Boolean | false | Server-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). | ||
rowCount | Number | null | Total server-side row count for manual pagination; lets the table compute page count when it doesn't hold the full dataset. | ||
pageCount | Number | null | Explicit total page count for manual pagination; overrides rowCount-derived count. | ||
expandable | Boolean | false | Opt-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). Pass expandable as a real boolean — a valueless attribute only coerces to true on Vue and Lit. | ||
expanded | any | null | ✓ | ExpandedState — { [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. | |
getRowId | Function | null | Row identity (originalRow, index, parentRow?) => string | number — the key rowSelection, expanded and the per-row caches use. Default null → table-core keys rows by position ("0", "1", … and "0.1" for sub-rows), so inserting or removing rows above a selected or expanded row moves that state onto whatever row now sits at its index. Supply it whenever rows can be added or removed while state is held (server push, live lists); the result is coerced to a string. | ||
getSubRows | Function | null | Table-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. | ||
groupable | Boolean | false | Opt-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). | ||
grouping | Array | null | ✓ | GroupingState — 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 the two-way grouping model (a non-null [] default would short-circuit it). All reads are null-guarded, so table-core still receives an array. | |
rowSelection | Object | {} | ✓ | 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. | |
columnVisibility | Object | {} | ✓ | VisibilityState — { [colId]: boolean }. Hidden columns drop automatically from header + body. Two-way: funnels a fresh object through visibility-change. | |
columnSizing | Object | {} | ✓ | ColumnSizingState — { [colId]: number }. Driven live by the pointer-drag resize handle (columnResizeMode: 'onChange'). Two-way: fires resize-change. | |
columnOrder | Array | [] | ✓ | ColumnOrderState — string[]. A fresh order array on reorder (never an in-place splice). Two-way: fires reorder-change. | |
columnPinning | Object | {…} | ✓ | ColumnPinningState — { left: string[], right: string[] }. Pinned columns get position: sticky + computed offsets. Defaults to { left: [], right: [] }. Two-way: fires pin-change. | |
stickyHeader | Boolean | false | Pure-CSS sticky header: the <thead> sticks to the top of the scroll container. | ||
interactionMode | String | "table" | 'table' (default, row-oriented, byte-behaviorally identical to a plain accessible table) | 'grid' — lights up the full WAI-ARIA grid interaction mode: role="grid", a roving single tab-stop, 2-D APG arrow-key cell navigation, range selection, and clipboard support. | ||
singleClickEdit | Boolean | false | Grid mode only. When true, a plain click on an editable cell opens its editor immediately (single-click-to-edit) instead of just activating the cell. Default false keeps click-to-activate (double-click opens the editor). Shift+click (range selection) and clicks on non-editable cells are unaffected. | ||
undoable | Boolean | false | Grid mode. When true, every committed data mutation (cell/row edit, paste, fill, cut, clear) becomes one undo step: Ctrl/Cmd+Z undoes, Ctrl/Cmd+Y or Ctrl/Cmd+Shift+Z redoes. Default false records no history and Ctrl+Z/Y are inert. | ||
undoLimit | Number | 100 | The maximum number of undo steps retained (oldest evicted past this depth). Only consulted when undoable is true. | ||
virtual | any | false | Opt-in windowing grammar: false (default, off — byte-identical to a non-virtual table) | true or 'rows' (vertical row windowing; true is byte-behavior-identical to every existing consumer, zero churn) | 'columns' (horizontal column windowing) | 'both' (both axes windowed). Row windowing renders only the visible slice of rows 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. Column windowing renders only the visible slice of leaf columns inside the same rdt-scroll container. An unrecognised string behaves as false. | ||
estimateRowHeight | Number | 40 | Estimated row height (px) — the first-paint seed for the windowing engine before any row has been measured. Only consulted when rows are windowed. When autoMeasure is true, later renders progressively refine the estimate from measured content; when autoMeasure is false this remains the explicit override for every render. | ||
autoMeasure | Boolean | false | Opt-in content-driven row-size estimation. When true, the windowing engine feeds estimateSize() a running mean of measured row heights instead of the fixed estimateRowHeight seed, so getTotalSize() converges to the true content total on a large table with variable-height rows. Falls back to estimateRowHeight before any row has been measured. Default false keeps the estimate fixed at estimateRowHeight for every render (today's behavior). | ||
maxHeight | String | '' | 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.
Attribute and listener fallthrough is OFF
Every component this package ships — DataTable, Column, DetailPanel, the four Editor* drop-ins, the three Filter* drop-ins and GroupBar — declares inherit-attrs="false" inherit-listeners="false", and none of them re-applies $attrs / $listeners anywhere in its template. An attribute or a native listener that is not a declared prop is dropped, not forwarded to the root element.
It is easy to trip over, because it is the opposite of the library-wide default (auto-fallthrough is on unless a component opts out), and nothing warns you:
html
<!-- dropped — `class`, `data-*` and the listener never reach the DOM -->
<DataTable class="my-table" data-analytics="orders" @click="onAnyClick" :data="rows" />Wrap the component when you need a hook of your own:
html
<div class="my-table" data-analytics="orders" @click="onAnyClick">
<DataTable :data="rows" />
</div>The same rule governs the drop-in editors and filters, and it is why a prop a drop-in does not declare cannot be passed through to it — autofocus on <EditorSelect> reaches the component only because EditorSelect declares an autofocus prop, not by fallthrough. Style the table through the public tokens or the stable .rozie-data-table* / .rdt-* class names rather than an injected class.
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.
Two distinct channels exist per slice, and they are easy to conflate. Every r-model: slice is wired to its target framework's own two-way binding mechanism — that wiring fires a model-update event whose name is per-target: Lit dispatches a kebab-case <slice>-change custom event (sorting-change, global-filter-change, column-filters-change, pagination-change, expanded-change, grouping-change, row-selection-change, column-visibility-change, column-sizing-change, column-order-change, column-pinning-change, plus data-change), React/Solid take an onSortingChange / onGlobalFilterChange / … prop, Vue/Svelte/Angular use their native two-way mechanism (update:sorting, a bindable, an [(ngModel)]-style output). Separately, eleven of the twelve slices also fire a hand-authored notification — a plain $emit call in the component's write funnel, using one name fixed across all six targets (the Change event column below), deliberately stemmed off a distinct word (sorting → sort-change, not sorting-change) so it can't camelCase into the same TS interface member the model-update channel auto-generates. This notification fires regardless of binding — it exists so you can observe a transition without binding the slice at all.
data is the exception: it has no hand-authored notification — its write funnel never calls $emit. The data-change name in the table below names only the model-update channel's Lit spelling; on React/Solid it is onDataChange, not data-change. To observe a committed data change without binding r-model:data, listen for cell-edit-commit / row-edit-commit instead (see the Events table below).
Model (r-model:) | Shape | Change event | Description |
|---|---|---|---|
data | TData[] | (none — see note above) | The 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-change | The sort state (header click; shift-click adds a secondary sort). |
globalFilter | string | filter-change | The global search string — narrows all columns. |
columnFilters | [{ id, value }] | filter-change | Per-column filter values (gated by each column's filterable). |
pagination | { pageIndex, pageSize } | page-change | The current page index + size. |
rowSelection | { [rowId]: true } | selection-change | The selected-row set (checkbox-only). |
expanded | { [rowId]: true } | true | expand-change | The expanded-row set (multi-expand; the true literal = all rows expanded). |
grouping | string[] | group-change | The ordered grouping key list (multi-column → nested groups). [] is ungrouped. |
columnVisibility | { [colId]: boolean } | visibility-change | Per-column shown/hidden state. |
columnSizing | { [colId]: number } | resize-change | Per-column widths (live during a resize drag). |
columnOrder | string[] | reorder-change | The full column order. |
columnPinning | { left: string[], right: string[] } | pin-change | Per-side pinned-column ids. |
The twelve Lit model-update event names, for reference: data-change, sorting-change, global-filter-change, column-filters-change, pagination-change, row-selection-change, expanded-change, grouping-change, column-visibility-change, column-sizing-change, column-order-change, column-pinning-change.
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).
| Event | Description |
|---|---|
sort-change | Fired when the sort state changes (header click / shift-click multi-sort / a sortColumn/clearSorting call). Payload: the fresh SortingState [{ id, desc }]. |
filter-change | Fired 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-change | Fired when pagination changes (prev/next, a page-size change, or a setPage/setRowsPerPage call). Payload: the fresh { pageIndex, pageSize }. |
selection-change | Fired when the row selection changes (a row/select-all checkbox toggle or a toggleAllRows/clearSelection call). Payload: the fresh RowSelectionState. |
expand-change | Fired 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-change | Fired 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-change | Fired when a column is shown/hidden (the column-toggle menu or a toggleColumnVisibility call). Payload: the fresh VisibilityState. |
resize-change | Fired live during a column resize drag (columnResizeMode: 'onChange'). Payload: the fresh ColumnSizingState. |
reorder-change | Fired when the column order changes. Column reorder is programmatic only — an applyColumnOrder call or a two-way columnOrder write; unlike visibility, resize and pin, no built-in drag or menu affordance ships. Payload: the fresh ColumnOrderState. |
pin-change | Fired when a column is pinned/unpinned (the per-header pin buttons or a pinColumn call). Payload: the fresh ColumnPinningState. |
activecell-change | Grid 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-commit | Fired 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-commit | Fired 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. |
row-activate | Fired when the user opens a row — a plain click on a body data row outside any control in the clicked cell (the selection checkbox, expander, links, inputs, drop-ins and an open editor don't count), in both modes; in grid mode also Enter on a non-editable cell that has no controls of its own (Enter on an editable cell still starts the edit). Not a shift/ctrl/meta click, a drag-select, or a singleClickEdit click on an editable cell. Group-header and detail rows never activate. Payload: { row, index, trigger } — row the original data object, index its position in the rendered model, trigger 'click' or 'keyboard'. |
range-change | Grid 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. |
visible-range-change | Requires row windowing (virtual). Fired when the rendered row window changes (overscan included), and once after mount. Payload: { start, end } over the full row space, end exclusive — with lazy rows (manual + rowCount + sparse data) that space is rowCount long. Deduped: a scroll that does not move the window emits nothing. See lazy loading. |
history-change | Requires undoable. Fired when undo/redo availability changes: always after an undo()/redo() call, and when a recorded edit flips canUndo/canRedo (edge-gated, so a streak of edits that leaves availability unchanged fires nothing). Payload: { canUndo: boolean, canRedo: boolean }. Drive undo/redo toolbar-button enablement from it. |
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.
| Method | Description |
|---|---|
sortColumn | Toggle (or set) the sort for a column — sortColumn(colId, desc?). Fires sort-change. |
clearSorting | Clear all sorting — clearSorting(). Resets to the unsorted core row model. Fires sort-change. |
getColumnDefs | Return the resolved ColumnDef[] (the id-keyed LWW union of the :columns array and the <Column> children). |
toggleAllRows | Select or clear all (filtered) rows — toggleAllRows(value). Fires selection-change. |
clearSelection | Clear the row selection — clearSelection(). Fires selection-change with {}. |
getSelectedRows | Return the original row data for the selected rows — getSelectedRows() → unknown[]. |
toggleRowExpanded | Toggle 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. |
expandAll | Open every expandable row — expandAll(). Fires expand-change (payload may be the true literal). |
collapseAll | Collapse every row — collapseAll(). Resets the expanded set to {}. Fires expand-change. |
getExpandedRows | Return the original row data for the currently-expanded rows — getExpandedRows() → unknown[] (empty when nothing is expanded). |
applyGrouping | Set 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.) |
clearGrouping | Clear all grouping — clearGrouping(). Resets to the ungrouped (flat) row model. Fires group-change with []. |
setPage | Go to a 0-based page index — setPage(idx). Fires page-change. |
setRowsPerPage | Set the page size — setRowsPerPage(size). Fires page-change. |
toggleColumnVisibility | Show/hide a column — toggleColumnVisibility(colId). Fires visibility-change. |
applyColumnOrder | Set the full column order — applyColumnOrder(order). Fires reorder-change. (Named applyColumnOrder, not setColumnOrder, to avoid colliding with React's auto-generated columnOrder model setter.) |
resetColumnSizing | Reset all column widths to their defaults — resetColumnSizing(). Fires resize-change. |
pinColumn | Pin a column to a side or unpin it — pinColumn(colId, side) where side is 'left' | 'right' | false. Fires pin-change. |
getFacetedUniqueValues | Return 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. |
getFacetedMinMaxValues | Return 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. |
editCell | Editing. 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. |
commitEditing | Editing. 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. |
editRow | Editing. 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. |
getSelectedRange | Return 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. |
focusCell | Grid mode. Move + DOM-focus the active cell by index — focusCell(rowIndex, colIndex) (coerced to integers and clamped to the visible model). Fires activecell-change. |
getActiveCell | Grid mode. Return the current active-cell position — getActiveCell() → { rowIndex, colIndex } (integers only; never a row object or DOM node). |
clearActiveCell | Grid mode. Reset the roving position to the entry cell (0,0) and exit interaction mode — clearActiveCell(). Does not emit (a reset, not a navigation). |
scrollToRow | Scroll a row into view on a virtual table — scrollToRow(index, options?), forwarding TanStack virtual-core's own ScrollToOptions ({ align?: 'start' | 'center' | 'end' | 'auto'; behavior?: 'auto' | 'smooth' | 'instant' }) unchanged to virtualizer.scrollToIndex. Independent of grid-mode focus: never moves the roving active cell and never fires activecell-change, and is callable in either interactionMode. No-op when rows are not windowed. |
getScrollElement | Return the DOM node the row and column virtualizer(s) scroll — getScrollElement() → HTMLElement | null. The supported replacement for reaching into the internal .rdt-scroll class selector; returns null when nothing is windowed. |
getRowIndexRelativeToPage | Convert an absolute display-order row index (the focusCell / getActiveCell / activecell-change space) to its page-relative index: getRowIndexRelativeToPage(absRow?); with no argument it converts the current active cell's row. In virtual mode (windowing replaces pagination) the absolute index is returned unchanged. Mirrors MUI's getRowIndexRelativeToVisibleRows. |
cut | Grid mode. Copy the current cell-range selection to the clipboard as TSV, then clear the source cells through the standard write funnel: cut() (the API twin of Ctrl+X). Read-only and validation-protected cells are left intact; each cleared cell fires cell-edit-commit; no-op while a header cell is active. |
undo | Requires undoable. Restore the data snapshot from before the most recent mutation (cell/row edit, paste, fill, cut): undo(). Replays through the standard write path, so it writes r-model:data — firing the data slice's per-target model-update event (Lit's data-change, React's onDataChange, etc.; see Models) — and fires history-change. The stack keeps up to undoLimit snapshots (oldest evicted). No-op when there is nothing to undo. |
redo | Requires undoable. Restore the most recently undone mutation: redo(). Same write path and events as undo. No-op when there is nothing to redo. A new recorded edit invalidates the redo stack (standard undo semantics). |
canUndo | Return whether an undo snapshot is available: canUndo() returns a boolean (always false when undoable is off). |
canRedo | Return whether a redo snapshot is available: canRedo() returns a boolean. |
clearHistory | Empty both the undo and redo stacks: clearHistory(). The table also clears its history automatically when the bound data is swapped externally (a new dataset should not inherit the old one's undo stack). |
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.
cell, colHeader, filter and editor each also have a per-column slot family — a statically-named fill per columnId (cell-price, filter-category, …) that takes precedence over the matching generic slot in the table below. See Per-column slot families for the full precedence/gate rules and Per-framework usage code for the exact per-target syntax (React/Solid slots, Svelte snippets, Lit .rozieSlots, Vue/Angular native #cell-<id> / [templates]).
| Slot | Params | Description |
|---|---|---|
placeholder | index, columnId | Lazy rows only (virtual + manual + rowCount + sparse data). Rendered in each data cell of a row not loaded yet; default a skeleton bar. index is the row's position in the full row space. |
cell | columnId, column, row, value | Custom cell renderer — switch on columnId to vary per column. A column it does not render shows the plain accessor value. On a group-header row row is a group descriptor, not a data record — guard with row.isGroupRow before reading record fields (0.3.2). |
cell-<columnId> | columnId, column, row, value | Family fill — a static per-column override of cell (e.g. #cell-price). No gate. See Per-column slot families. |
colHeader | columnId, column, label | Custom header renderer — switch on columnId. Falls back to the plain header label. |
colHeader-<columnId> | columnId, column, label | Family fill — a static per-column override of colHeader. No gate. See Per-column slot families. |
selectAll | checked, indeterminate, toggle | Override the select-all header (only when selectionMode="multiple"). indeterminate is true on a partial selection. |
selectCell | row, checked, toggle | Override the per-row select checkbox (only when selectionMode="multiple"). On a group-header row row is a group descriptor, not a data record (0.3.2). |
detail | row | Custom expanded-row content rendered under an expanded row (only when expandable and no getSubRows). The React render-prop edge (documented divergence). |
groupBar | grouping, groupableColumns, applyGrouping, clearGrouping | Headless 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. groupableColumns lists every groupable leaf column in declaration order — including leaves nested under a multi-level group header, and excluding the group headers themselves, which carry no accessor and cannot be a grouping key (0.3.2). Opt a leaf out with groupable: false. 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). |
filter | columnId, value, uniqueValues, minMax, setFilter | Headless faceted-filter UI (only when a column is filterable). value is the column's current filter value; 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. |
filter-<columnId> | columnId, value, uniqueValues, minMax, setFilter | Family fill — a static per-column override of filter. Requires the column to declare filterable, the same gate as filter itself. See Per-column slot families. |
editor | columnId, column, row, value, commit, cancel, autofocus | Custom 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 is an opaque passthrough; autofocus tells the editor whether the host wants it to take initial focus (drive your input's autofocus/focus() from it). row is the data record — a group-header row can never enter edit, so this slot never renders on one (0.3.2). Pair it with the drop-in editor components. The React render-prop edge (documented divergence). |
editor-<columnId> | columnId, column, row, value, commit, cancel, autofocus | Family fill — a static per-column override of editor. Requires the column to declare editor="custom", the same gate as editor itself. See Per-column slot families. |
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.