Introducing PrimeReact v11-alpha 🎉Discover Now

useTree

Hooks that manage tree state, keyboard navigation, selection, and drag-drop.

  • Documents
basic-demo

Usage#

import { useTree, useTreeNode } from '@primereact/headless/tree';
const tree = useTree({ value: nodes, selectionMode: 'single' });
const { rootProps } = tree;
 
const treeNode = useTreeNode({ node: nodes[0], context: tree, index: 0 });
const { state, nodeProps, contentProps } = treeNode;
const toggleProps = tree.getToggleProps(nodes[0]);

useTree manages root-level state while useTreeNode consumes that context to return prop objects for each node element. See Primitive for a component-based API.

Features#

  • Two-hook architecture — useTree owns the root state; useTreeNode consumes context and returns per-node props, letting you render any node shape
  • Selection modes — single, multiple, and checkbox with automatic parent/child propagation in checkbox mode
  • Expansion state — controlled or uncontrolled expandedKeys with onExpandedChange for hydration or persistence
  • Drag-and-drop — opt-in with scope validation so trees can transfer nodes within themselves or to a compatible tree
  • Filtering and typeahead — filterProps for a search input plus typeahead across visible nodes
  • Reactive per-node state — state.expanded, state.selected, and friends drive conditional child rendering

Working with callbacks#

Controlled expansion#

Use expandedKeys with onExpandedChange to persist expansion state or hydrate from the server.

const [expandedKeys, setExpandedKeys] = React.useState<TreeExpandedKeys>({ '0': true });
 
const tree = useTree({
    value: nodes,
    expandedKeys,
    onExpandedChange: (e) => setExpandedKeys(e.value)
});
 
<div {...rootProps}>
    <ul {...tree.getListProps(false)}>
        <li {...nodeProps}>
            <div {...contentProps}>
                <button {...toggleProps}></button>
            </div>
        </li>
    </ul>
</div>;

Selection in checkbox mode#

checkbox selection stores { checked, partialChecked } per key and handles parent-child propagation for you.

const [selectionKeys, setSelectionKeys] = React.useState({});
 
const tree = useTree({
    value: nodes,
    selectionMode: 'checkbox',
    selectionKeys,
    onSelectionChange: (e) => setSelectionKeys(e.value)
});

Drag-and-drop with scopes#

Enable drag-drop on both sides and use scopes to restrict which trees can exchange nodes.

const tree = useTree({
    value: nodes,
    draggableNodes: true,
    droppableNodes: true,
    draggableScope: 'tasks',
    droppableScope: 'tasks',
    onValueChange: (e) => setNodes(e.value)
});

Wiring up a filter input#

Spread filterProps onto any input — the hook handles the search string, keyboard, and autoComplete="off".

<input {...tree.filterProps} placeholder="Search" />

Rendering children with state.expanded#

Inside a recursive node component, read state.expanded from useTreeNode to mount or unmount children.

function TreeNodeItem({ node, index }) {
    const { state, nodeProps, contentProps } = useTreeNode({ node, context: tree, index });
 
    return (
        <li {...nodeProps}>
            <div {...contentProps}>{node.label}</div>
            {state.expanded && node.children && (
                <ul {...tree.getListProps(true)}>
                    {node.children.map((child, i) => (
                        <TreeNodeItem key={child.key} node={child} index={i} />
                    ))}
                </ul>
            )}
        </li>
    );
}

Styling with data attributes#

Every prop object includes data-scope="tree" and a data-part attribute. State-dependent attributes are added automatically to enable CSS-only styling.

rootProps#

AttributeDescription
data-scope"tree"
data-part"root"
data-drag-hoverPresent when a node is being dragged over root

nodeProps#

AttributeDescription
data-scope"tree"
data-part"node"
data-node-keyNode key value
data-expandedPresent when node is expanded (non-leaf only)
data-collapsedPresent when node is collapsed (non-leaf only)
data-selectedPresent when node is selected
data-leafPresent when node is a leaf
data-disabledPresent when node is disabled

contentProps#

AttributeDescription
data-scope"tree"
data-part"content"
data-selectedPresent when selected or checked
data-selectablePresent when selectable
data-expandedPresent when expanded (non-leaf only)
data-collapsedPresent when collapsed (non-leaf only)
data-leafPresent when leaf node
data-checkedPresent when checked (checkbox mode)
data-partial-checkedPresent when partially checked (checkbox mode)
data-disabledPresent when disabled
data-drop-hoverPresent when a dragged node hovers over content

getToggleProps#

AttributeDescription
data-scope"tree"
data-part"toggle"
data-expandedPresent when node is expanded
data-collapsedPresent when node is collapsed

dropPointProps#

AttributeDescription
data-scope"tree"
data-part"drop-point"
[data-scope='tree'][data-part='content'] {
    padding: 0.25rem 0.5rem;
}
 
[data-scope='tree'][data-part='content'][data-selected] {
    background-color: rgba(var(--primary-rgb), 0.1);
}
 
[data-scope='tree'][data-part='content'][data-expanded] {
    font-weight: 600;
}
 
[data-scope='tree'][data-part='node'][data-node-key='0'] {
    font-weight: bold;
}

API#

useTree#

NameTypeDefault
valueTreeNodeData[]—
An array of treenodes.
expandedKeysTreeExpandedKeys—
A record of keys to represent the state of the tree expansion state in controlled mode.
defaultExpandedKeysTreeExpandedKeys—
The default expanded keys when used in uncontrolled mode.
selectionKeysTreeSelectionKeys | TreeCheckboxSelectionKeys—
A record of keys to represent the selection state in controlled mode. For single/multiple mode: Record<string, boolean> For checkbox mode: Record<string, { checked: boolean, partialChecked: boolean }>
defaultSelectionKeysTreeSelectionKeys | TreeCheckboxSelectionKeys—
The default selected keys when used in uncontrolled mode.
selectionMode"checkbox" | "multiple" | "single"—
Defines the selection mode.
metaKeySelectionbooleanfalse
Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect multiple items. When set to false selection of each item can be toggled individually.
highlightOnSelectbooleanfalse
Highlights automatically the first item.
draggableNodesboolean—
Whether the tree nodes can be dragged.
droppableNodesboolean—
Whether the tree can accept dropped nodes.
draggableScopestring | string[]—
A unique identifier for the draggable scope.
droppableScopestring | string[]—
A unique identifier for the droppable scope.
validateDropbooleanfalse
Whether to validate drops before processing.
onExpandedChange(event: useTreeExpandedChangeEvent) => void—
Callback fired when the tree's expanded keys change.
onSelectionChange(event: useTreeSelectionChangeEvent) => void—
Callback fired when the tree's selection changes.
onToggle(event: useTreeToggleEvent) => void—
Callback fired when a node is toggled.
onExpand(event: useTreeExpandEvent) => void—
Callback fired when a node is toggled.
onCollapse(event: useTreeCollapseEvent) => void—
Callback fired when a node is toggled.
onClick(event: useTreeClickEvent) => void—
Callback fired when a node is clicked.
onSelect(event: useTreeSelectEvent) => void—
Callback fired when a node is selected.
onUnselect(event: useTreeUnselectEvent) => void—
Callback fired when a node is unselected.
onNodeDrop(event: useTreeNodeDropEvent) => void—
Callback fired when a node is dropped.
onDragEnter(event: useTreeDragEnterEvent) => void—
Callback fired when drag enters the tree.
onDragLeave(event: useTreeDragLeaveEvent) => void—
Callback fired when drag leaves the tree.
onValueChange(event: useTreeValueChangeEvent) => void—
Callback fired when the tree value changes (for drag-drop).

useTreeNode#

NameTypeDefault

Accessibility#

Arrow keys navigate nodes, Right expands or moves to first child, Left collapses or moves to parent, and Enter selects. See Primitive for full WAI-ARIA compliance details.