Introducing PrimeReact v11-alpha 🎉Discover Now

useTreeTable

Hierarchical data table built on useDataTable with treeMode enabled — sort, filter, paginate, select, expand, and edit tree-shaped data.

NameSizeType
basic-demo

Usage#

TreeTable is not a separate hook — it is useDataTable with treeMode: true. The hook flattens the visible part of the tree (respecting expandedKeys), so every other feature (sort, filter, pagination, selection, editing, reorder, export) works the same way as on flat data.

import { useDataTable } from '@primereact/headless/datatable';
const tree = useDataTable({
    data: nodes,
    dataKey: 'key',
    treeMode: true,
    expandedKeys,
    onExpandedChange: (e) => setExpandedKeys(e.value)
});

Nodes are objects of the shape { key, data, children? }. Flat rows produced by the hook are stamped with helpers used by the renderer:

FieldTypeMeaning
_treeLevelnumberZero-based depth in the tree (used for indentation and aria-level).
_treeHasChildrenbooleanWhether the row has children (drives the expander vs. spacer).
_treePosInSetnumberOne-based position among siblings (aria-posinset).
_treeSetSizenumberTotal siblings at this depth (aria-setsize).

Features#

All useDataTable features work the same way; the table role becomes treegrid and rows pick up tree-aware ARIA attributes. A few things behave differently in tree mode:

  • Filter — column filters and the global filter keep ancestor nodes when any descendant matches, so the result stays connected to its roots
  • Selection — checkbox selection cascades to descendants; partially-selected parents are reported through selection.isPartiallySelected(key)
  • Pagination — the paginator slices root-level nodes only; expanded children stay inside the same page

Working with callbacks#

Controlled expansion#

const [expandedKeys, setExpandedKeys] = React.useState<Record<string, boolean>>({ '0': true });
 
const tree = useDataTable({
    data: nodes,
    dataKey: 'key',
    treeMode: true,
    expandedKeys,
    onExpandedChange: (e) => setExpandedKeys(e.value)
});

Filter + sort + pagination#

Pass the same filters / sortField / paginator props as on a flat DataTable; the hook re-runs them against the tree.

const tree = useDataTable({
    data: nodes,
    treeMode: true,
    paginator: true,
    rows: 10,
    filters,
    onFilter: (e) => setFilters(e.filters),
    sortField,
    sortOrder,
    onSortChange: (e) => {
        setSortField(e.field);
        setSortOrder(e.order);
    }
});

API#

useDataTable#

NameTypeDefault
dataRecord<string, unknown>[] | object[]
An array of objects to display.
defaultValuestring
Default sort value for uncontrolled mode.
valuestring
Sort field value for controlled mode.
dataKeystring
A property to uniquely identify each row in the data.
loadingbooleanfalse
Whether the data is currently being loaded.
lazybooleanfalse
Defines if data is loaded and interacted with in lazy manner.
totalRecordsnumber0
Number of total records, used in lazy mode.
scrollablebooleanfalse
When enabled, the table can be scrolled horizontally and/or vertically.
scrollHeightstring
Height of the scroll viewport in fixed pixels or the "flex" keyword for a dynamic size.
sortFieldstringundefined
Property name to sort by in single-sort mode.
sortOrderSortOrderundefined
Sort order for single-sort mode.
defaultSortFieldstringundefined
Default sort field for uncontrolled single-sort mode.
defaultSortOrderSortOrderundefined
Default sort order for uncontrolled single-sort mode.
multiSortMetaSortMeta[]undefined
An array of SortMeta objects for multi-column sorting (controlled).
defaultMultiSortMetaSortMeta[]undefined
Initial multi-column sort metadata for uncontrolled mode.
onSortChange(event: DataTableSortEvent) => void
Callback invoked when the sort state changes.
removableSortbooleanfalse
When true, clicking a sorted column header a third time removes the sort.
nullSortOrdernumber1
Determines where null values are placed during sort. 1 = nulls last (default), -1 = nulls first.
selectionMode"multiple" | "single"
Defines the selection mode. 'single' allows one row, 'multiple' allows many.
metaKeySelectionbooleanfalse
When true, row click selection requires Ctrl/Cmd key. Without it, click selects only that row. Shift+Click extends range. Only applies when selectionMode is set.
selectedKeysSelectionKeysundefined
The selection keys for controlled mode.
defaultSelectedKeysSelectionKeysundefined
The default selection keys for uncontrolled mode.
onSelectionChange(event: DataTableSelectionEvent) => voidundefined
Callback invoked when the selection changes.
pagenumberundefined
Current page number for controlled pagination (0-indexed).
defaultPagenumber0
Default page number for uncontrolled pagination (0-indexed).
rowsnumberundefined
Number of rows to display per page for controlled mode.
defaultRowsnumber10
Default number of rows to display per page for uncontrolled mode.
rowsPerPageOptionsnumber[]undefined
Array of integer values to display inside the rows per page dropdown.
paginatorbooleanfalse
Whether pagination is enabled.
onPageChange(event: DataTablePageEvent) => void
Callback invoked when the page or rows per page changes.
expandedKeysExpandedKeysundefined
The expanded keys map for controlled row expansion.
defaultExpandedKeysExpandedKeysundefined
The default expanded keys map for uncontrolled row expansion.
onExpandedChange(event: DataTableExpansionEvent) => void
Callback invoked when the expanded keys change.
groupFieldstringundefined
The field name to group rows by.
reorderableColumnsbooleanfalse
When enabled, columns can be reordered using drag and drop.
onColumnReorder(event: DataTableColumnReorderEvent) => void
Callback invoked when columns are reordered.
resizableColumnsbooleanfalse
When enabled, columns can be resized using drag and drop.
columnResizeModeColumnResizeMode'fit'
Defines whether the overall table width should change on column resize. 'fit' mode keeps total width the same. 'expand' mode increases total width.
onColumnResizeEnd(event: DataTableColumnResizeEvent) => void
Callback invoked when a column resize ends.
editModeDataTableEditModeundefined
Defines the editing mode.
editingKeysEditingKeysundefined
The editing keys map for controlled row editing.
defaultEditingKeysEditingKeysundefined
The default editing keys for uncontrolled row editing.
onEditingKeysChange(event: DataTableEditingEvent) => void
Callback invoked when the editing keys change.
onRowEditInit(event: DataTableRowEditEvent) => void
Callback invoked when a row edit is initiated.
onRowEditSave(event: DataTableRowEditEvent) => void
Callback invoked when a row edit is saved.
onRowEditCancel(event: DataTableRowEditEvent) => void
Callback invoked when a row edit is cancelled.
onCellEditInit(event: { originalEvent: SyntheticEvent; field: string; rowIndex: number }) => void
Callback invoked when a cell edit is initiated.
onCellEditComplete(event: DataTableCellEditEvent) => void
Callback invoked when a cell edit completes.
onCellEditCancel(event: DataTableCellEditEvent) => void
Callback invoked when a cell edit is cancelled.
filtersDataTableFilterMetaundefined
Filter metadata for controlled mode.
defaultFiltersDataTableFilterMetaundefined
Default filter metadata for uncontrolled mode.
globalFilterstring
Global filter value applied across globalFilterFields.
globalFilterFieldsstring[]undefined
An array of field names to search with globalFilter.
filterDelaynumber0
Delay in ms before applying filter (for debounce).
onFilter(event: DataTableFilterEvent) => void
Callback invoked when filters change.
reorderableRowsbooleanfalse
When enabled, rows can be reordered using drag and drop.
onRowReorder(event: DataTableRowReorderEvent) => void
Callback invoked when rows are reordered.
rowClassName(data: Record<string, unknown>, options: { index: number; props: useDataTableProps }) => string
A function that returns a className for a given row.
onLazyLoad(event: DataTableLazyLoadEvent) => void
Callback invoked when lazy loading is triggered (page, sort, filter change in lazy mode).
onRowClick(event: DataTableRowMouseEvent) => void
Callback fired when a row is clicked. Does NOT fire when the click originates on interactive content (buttons, inputs, checkboxes, radios) — those bubble their own semantics.
onRowDoubleClick(event: DataTableRowMouseEvent) => void
Callback fired on row double-click.
onRowContextMenu(event: DataTableRowMouseEvent) => void
Callback fired on row right-click (contextmenu). Does not prevent the default menu — call `event.originalEvent.preventDefault()` in the handler if you want to.
rowHoverbooleanfalse
When enabled, rows highlight on mouse hover via `data-row-hover` attribute on root.
highlightOnSelectbooleantrue
When enabled, selected rows are highlighted via `data-highlight-on-select` attribute on root.
treeModebooleanfalse
When enabled, data is treated as a tree structure with `key` , `data` , and `children` fields. Tree nodes are flattened internally and sort, filter, pagination operate on the tree structure. Pagination applies to root-level nodes only.
size"small" | "large"undefined
Table size variant. Adjusts cell padding and font size via CSS.
stripedRowsbooleanfalse
When enabled, rows are rendered with alternating background colors.
showGridlinesbooleanfalse
When enabled, borders are displayed between cells.

useDataTableRow#

NameTypeDefault
itemRecord<string, unknown>
The data object for this row.
indexnumber0
The index of the row in the data array.
contextuseDataTableInstance
The parent datatable instance providing state and methods.

Accessibility#

role="treegrid" is applied to the table; rows expose aria-level, aria-expanded, aria-posinset, aria-setsize. Expander buttons emit aria-expanded and a descriptive aria-label. See Primitive for full WAI-ARIA compliance details.