Tree is used to display hierarchical data.
import { Tree } from 'primereact/tree';
<script src="https://unpkg.com/primereact/core/core.min.js"></script>
Tree component requires an array of TreeNode objects as its value.
Name | Type | Default | Description |
---|---|---|---|
key | any | null | Unique key of the node. |
label | string | null | Label of the node. |
data | any | null | Data represented by the node. |
icon | string | null | Icon of the node to display next to content. |
children | TreeNode[] | null | An array of treenodes as children. |
style | string | null | Inline style of the node. |
className | string | null | Style class of the node. |
draggable | boolean | true | Whether the node is draggable when dragdrop is enabled. |
droppable | boolean | true | Whether the node is droppable when dragdrop is enabled. |
selectable | boolean | null | Whether the node is selectable when selection mode is enabled. |
leaf | boolean | null | Specifies if the node has children. Used in lazy loading. |
<Tree value={data} />
const data: [
{
"key": "0",
"label": "Documents",
"data": "Documents Folder",
"icon": "pi pi-fw pi-inbox",
"children": [{
"key": "0-0",
"label": "Work",
"data": "Work Folder",
"icon": "pi pi-fw pi-cog",
"children": [{ "key": "0-0-0", "label": "Expenses.doc", "icon": "pi pi-fw pi-file", "data": "Expenses Document" }, { "key": "0-0-1", "label": "Resume.doc", "icon": "pi pi-fw pi-file", "data": "Resume Document" }]
},
{
"key": "0-1",
"label": "Home",
"data": "Home Folder",
"icon": "pi pi-fw pi-home",
"children": [{ "key": "0-1-0", "label": "Invoices.txt", "icon": "pi pi-fw pi-file", "data": "Invoices for this month" }]
}]
},
{
"key": "1",
"label": "Events",
"data": "Events Folder",
"icon": "pi pi-fw pi-calendar",
"children": [
{ "key": "1-0", "label": "Meeting", "icon": "pi pi-fw pi-calendar-plus", "data": "Meeting" },
{ "key": "1-1", "label": "Product Launch", "icon": "pi pi-fw pi-calendar-plus", "data": "Product Launch" },
{ "key": "1-2", "label": "Report Review", "icon": "pi pi-fw pi-calendar-plus", "data": "Report Review" }]
},
{
"key": "2",
"label": "Movies",
"data": "Movies Folder",
"icon": "pi pi-fw pi-star-fill",
"children": [{
"key": "2-0",
"icon": "pi pi-fw pi-star-fill",
"label": "Al Pacino",
"data": "Pacino Movies",
"children": [{ "key": "2-0-0", "label": "Scarface", "icon": "pi pi-fw pi-video", "data": "Scarface Movie" }, { "key": "2-0-1", "label": "Serpico", "icon": "pi pi-fw pi-video", "data": "Serpico Movie" }]
},
{
"key": "2-1",
"label": "Robert De Niro",
"icon": "pi pi-fw pi-star-fill",
"data": "De Niro Movies",
"children": [{ "key": "2-1-0", "label": "Goodfellas", "icon": "pi pi-fw pi-video", "data": "Goodfellas Movie" }, { "key": "2-1-1", "label": "Untouchables", "icon": "pi pi-fw pi-video", "data": "Untouchables Movie" }]
}]
}
]
Tree expansion state is managed in two ways, in uncontrolled mode only initial expanded state of a node can be defined using expandedKeys property whereas in controlled mode expandedKeysproperty along with onToggle properties are used for full control over the state. If you need to expand or collapse the state of nodes programmatically then controlled mode should be used. Example below demonstrates both cases;
import React, { Component } from 'react';
import { Tree } from 'primereact/tree';
import { Button } from 'primereact/button';
import { NodeService } from '../service/NodeService';
export const TreeDemo = () => {
const [nodes, setNodes] = useState(null);
const [expandedKeys, setExpandedKeys] = useState({});
useEffect(() => {
nodeService = new NodeService();
nodeService.getTreeNodes().then(data => setNodes(data));
}, [])
const toggleMovies = () => {
let expandedKeys = {...expandedKeys};
if (expandedKeys['2'])
delete expandedKeys['2'];
else
expandedKeys['2'] = true;
setExpandedKeys(expandedKeys);
}
return (
<div>
<h3 className="first">Uncontrolled</h5>
<Tree value={nodes} />
<h5>Controlled</h5>
<Button onClick={toggleMovies} label="Toggle Movies" />
<Tree value={nodes} expandedKeys={expandedKeys}
onToggle={e => setExpandedKeys(e.value)} style={{marginTop: '.5em'}} />
</div>
)
}
Tree supports single, multiple and checkbox selection modes. Define selectionMode, selectionKeys and onSelectionChange properties to control the selection. In single mode, selectionKeys should be a single value whereas in multiple or checkbox modes an array is required. By default in multiple selection mode, metaKey is necessary to add to existing selections however this can be configured with metaKeySelection property. Note that in touch enabled devices, Tree does not require metaKey.
import React, {Component} from 'react';
import {Tree} from 'primereact/tree';
import {NodeService} from '../service/NodeService';
export const TreeSelectionDemo = () => {
const [nodes, setNodes] = useState(null);
const [selectedNodeKey] = useState(null);
const [selectedNodeKeys1] = useState(null);
const [selectedNodeKeys2] = useState(null);
const [selectedNodeKeys3] = useState(null);
useEffect(() => {
nodeService = new NodeService();
nodeService.getTreeNodes().then(data => setNodes(data));
}, [])
return (
<div>
<h5>Single Selection</h5>
<Tree value={nodes} selectionMode="single" selectionKeys={selectedNodeKey} onSelectionChange={e => setSelectedNodeKey(e.value)} />
<h5>Multiple Selection with MetaKey</h5>
<Tree value={nodes} selectionMode="multiple" selectionKeys={selectedNodeKeys1} onSelectionChange={e => setSelectedNodeKeys1(e.value)} />
<h5>Multiple Selection without MetaKey</h5>
<Tree value={nodes} selectionMode="multiple" metaKeySelection={false} selectionKeys={selectedNodeKeys2} onSelectionChange={e => setSelectedNodeKeys2(e.value)} />
<h5>Checkbox Selection</h5>
<Tree value={nodes} selectionMode="checkbox" selectionKeys={selectedNodeKeys3} onSelectionChange={e => setSelectedNodeKeys3(e.value)} />
</div>
)
}
Lazy loading is implemented using the onExpand event by adding children to the expanded node. leaf property should be enabled to indicate the node has children but not yet loaded. Here is a in-memory demo that loads generated nodes on expand event to imitate a remote call with a timeout. Notice the usage of loading property as well to give users a feedback about the loading process.
import React, {Component} from 'react';
import {Tree} from 'primereact/tree';
import {NodeService} from '../service/NodeService';
export const TreeLazyDemo = () => {
const [nodes, setNodes] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
nodeService = new NodeService();
setTimeout(() => {
nodeService.getTreeNodes().then(data => {
setNodes(data);
setLoading(false);
});
}, 2000);
}, [])
const loadOnExpand = (event) => {
if (!event.node.children) {
setLoading(true)
setTimeout(() => {
let node = {...event.node};
node.children = [];
for (let i = 0; i < 3; i++) {
node.children.push({
key: node.key + '-' + i,
label: 'Lazy ' + node.label + '-' + i
});
}
let value = [...nodes];
value[parseInt(event.node.key, 10)] = node;
setNodes(value);
setLoading(false);
}, 500);
}
}
return (
<Tree value={nodes} onExpand={loadOnExpand} loading={loading} />
)
}
label property of a node is used to display as the content by default. Templating is supported as well with the nodeTemplate callback that gets the node instance and returns JSX. For custom filter support define a filterTemplate function that gets the option instance as a parameter and returns the content for the filter element. Example below is a sample tree based navigation of React docs.
import React, { Component, useState, useRef } from 'react';
import { Tree } from 'primereact/tree';
export const TreeTemplatingDemo = () => {
const [nodes, setNodes] = useState(createNavigation());
const [filterValue, setFilterValue] = useState('');
const filterInputRef = useRef();
const createNavigation = () => {
return [
{
label: 'Insallation',
children: [
{label: 'Getting Started', url:'https://reactjs.org/docs/getting-started.html'},
{label: 'Add React', url: 'https://reactjs.org/docs/add-react-to-a-website.html'},
{label: 'Create an App', url:'https://reactjs.org/docs/create-a-new-react-app.html'},
{label: 'CDN Links', url: 'https://reactjs.org/docs/cdn-links.html'}
]
},
{
label: 'Main Concepts',
children: [
{label: 'Hello World', url: 'https://reactjs.org/docs/hello-world.html'},
{label: 'Introducing JSX', url: 'https://reactjs.org/docs/introducing-jsx.html'},
{label: 'Rendering Elements', url: 'https://reactjs.org/docs/rendering-elements.html'},
{label: 'Components and Props', url: 'https://reactjs.org/docs/components-and-props.html'},
{label: 'State and LifeCycle', url: 'https://reactjs.org/docs/state-and-lifecycle.html'},
{label: 'Handling Events', url: 'https://reactjs.org/docs/handling-events.html'}
]
}
];
}
const nodeTemplate = (node, options) => {
let label = <b>{node.label}</b>;
if (node.url) {
label = <a href={node.url}>{node.label}</a>;
}
return (
<span className={options.className}>
{label}
</span>
)
}
const filterTemplate = (options) => {
let {filterOptions} = options;
return (
<div className="flex gap-2">
<InputText value={filterValue} ref={filterInputRef} onChange={(e) => myFilterFunction(e, filterOptions)} />
<Button label="Reset" onClick={() => myResetFunction(filterOptions)} />
</div>
)
}
const myResetFunction = (options) => {
setFilterValue('');
options.reset();
filterInputRef && filterInputRef.current.focus()
}
const myFilterFunction = (event, options) => {
let _filterValue = event.target.value;
setFilterValue(_filterValue);
options.filter(event);
}
return (
<Tree value={nodes} nodeTemplate={nodeTemplate} filter filterTemplate={filterTemplate}/>
)
}
Tree nodes can be reordered using dragdrop by setting dragdropScope property to a unique variable and updating the new value at onDragDrop callback. The value of the dragdropScope must be unique to provide intervention from other draggable elements on the page.
import React, {Component} from 'react';
import {Tree} from 'primereact/tree';
import {NodeService} from '../service/NodeService';
export const TreeDragDropDemo = () => {
const [nodes, setNodes] = useState(null);
useEffect(() => {
nodeService = new NodeService();
nodeService.getTreeNodes().then(data => setNodes(data));
}, [])
return (
<div>
<Tree value={nodes} dragdropScope="demo" onDragDrop={event => setNodes(event.value)} />
</div>
)
}
Filtering is enabled by setting the filter property to true, by default label property of a node is used to compare against the value in the text field, in order to customize which field(s) should be used during search define filterBy property.
In addition filterMode specifies the filtering strategy. In lenient mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand, in strict mode when the query matches a node, filtering continues on all descendants.
<Tree value={nodes} filter />
<Tree value={nodes} filter filterBy="data.name,data.age" />
<Tree value={nodes} filter filterMode="strict" />
One or more ContextMenu instances can be attached to nodes. Similar to selection, separate contextMenuSelectionKey and onContextMenuSelectionChange properties are necesary to manage the selected node with right click. In addition, a context menu can either be displayed at onContextMenu event. Since this event also passes the node instance, you may choose to display a different context menu for a particular node.
import React, { Component } from 'react';
import {Tree} from 'primereact/tree'
import {ContextMenu} from 'primereact/contextmenu';
import {Toast} from 'primereact/toast';
import {NodeService} from '../service/NodeService';
export const TreeContextMenuDemo = () => {
const [nodes, setNodes] = useState(null);
const [expandedKeys, setExpandedKeys] = useState({});
const [selectedNodeKey, setSelectedNodeKey] = useState(null);
const toast = useRef(null);
const cm = useRef(null);
const menu = [
{
label: 'View Key',
icon: 'pi pi-search',
command: () => {
toast.current.show({severity: 'success', summary: 'Node Key', detail: selectedNodeKey});
}
},
{
label: 'Toggle',
icon: 'pi pi-cog',
command: () => {
let expandedKeys = {...expandedKeys};
if (expandedKeys[selectedNodeKey])
delete expandedKeys[selectedNodeKey];
else
expandedKeys[selectedNodeKey] = true;
setExpandedKeys(expandedKeys);
}
}
];
useEffect(() => {
nodeService = new NodeService();
nodeService.getTreeNodes().then(data => setNodes(data));
}, [])
return (
<div>
<Toast ref={toast} />
<ContextMenu model={menu} ref={cm} />
<Tree value={nodes} expandedKeys={expandedKeys} onToggle={e => setExpandedkeys(e.value)}
onContextMenuSelectionChange={event => setSelectedNodeKey(event.value)}
onContextMenu={event => cm.current.show(event.originalEvent)} />
</div>
)
}
Name | Type | Default | Description |
---|---|---|---|
id | string | null | Unique identifier of the element. |
value | array | null | An array of treenodes. |
selectionMode | string | null | Defines the selection mode, valid values "single", "multiple", and "checkbox". |
selectionKeys | any | null | A single or an array of keys to control the selection state. |
contextMenuSelectionKey | any | null | A single key to control the selection with the context menu. |
expandedKeys | array | null | An array of keys to represent the state of the tree expansion state in controlled mode. |
style | object | null | Inline style of the component. |
className | string | null | Style class of the component. |
contentStyle | object | null | Inline style of the tree content. |
contentClassName | string | null | Style class of the tree content. |
metaKeySelection | boolean | true | Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. |
propagateSelectionUp | boolean | true | Whether checkbox selections propagate to ancestor nodes. |
propagateSelectionDown | boolean | true | Whether checkbox selections propagate to descendant nodes. |
loading | boolean | false | Whether to display loading indicator. |
loadingIcon | string | pi pi-spin | Icon to display when tree is loading. |
dragdropScope | string | false | Unique key to enable dragdrop functionality. |
header | any | null | The template of header. |
footer | any | null | The template of footer. |
ariaLabel | string | false | Used to define a string that labels the component. |
ariaLabelledBy | string | null | Contains the element IDs of labels. |
nodeTemplate | any | false | Template of node element. |
filterTemplate | any | null | Template of filter element. |
togglerTemplate | any | null | Template of toggler element. |
filterTemplate | any | null | Template of filter element. |
showHeader | boolean | true | Whether to show the header or not. |
filter | boolean | false | When specified, displays an input field to filter the items. |
filterValue | string | null | When filtering is enabled, the value of input field. |
filterBy | string | label | When filtering is enabled, filterBy decides which field or fields (comma separated) to search against. |
filterMode | string | lenient | Mode for filtering valid values are "lenient" and "strict". Default is lenient. |
filterPlaceholder | string | null | Placeholder text to show when filter input is empty. |
filterLocale | string | undefined | Locale to use in filtering. The default locale is the host environment's current locale. |
disabled | boolean | false | When present, it specifies that the component should be disabled. |
Name | Parameters | Description |
---|---|---|
onSelect | event.originalEvent: browser event event.node: Selected node instance. | Callback to invoke when a node is selected. |
onUnselect | event.originalEvent: browser event event.node: Unselected node instance. | Callback to invoke when a node is unselected. |
onExpand | event.originalEvent: browser event event.node: Expanded node instance. | Callback to invoke when a node is expanded. |
onCollapse | event.originalEvent: browser event event.node: Collapsed node instance. | Callback to invoke when a node is collapsed. |
onSelectionChange | event.originalEvent: browser event event.value: Selected node key(s). | Callback to invoke when selection changes. |
onContextMenuSelectionChange | event.originalEvent: browser event event.value: Selected node key. | Callback to invoke when selection changes with a context menu. |
onToggle | event.originalEvent: browser event event.node: Toggled node instance. | Callback to invoke when a node is toggled. |
onDragDrop | event.originalEvent: browser event event.value: New value after the dragdrop. | Callback to invoke when a node is selected. |
onContextMenu | event.originalEvent: browser event event.node: Selected node instance. | Callback to invoke when a node is selected with a context menu. |
onFilterValueChange | event.originalEvent: Browser event event.value: the filtered value | Callback to invoke when filter value changes. |
onNodeClick | event.originalEvent: Browser event event.node: the current node | Callback to invoke when the node is clicked. |
onNodeDoubleClick | event.originalEvent: Browser event event.node: the current node | Callback to invoke when the node is double-clicked. |
Name | Parameters | Description |
---|---|---|
filter | value: the filter value | Filters the data. |
Following is the list of structural style classes
Name | Element |
---|---|
p-tree | Main container element |
p-tree-horizontal | Main container element in horizontal mode |
p-tree-container | Container of nodes |
p-treenode | A treenode element |
p-treenode-content | Content of a treenode |
p-treenode-toggler | Toggle element |
p-treenode-toggler-icon | Toggle icon |
p-treenode-icon | Icon of a treenode |
p-treenode-label | Label of a treenode |
p-treenode-children | Container element for node children |
This section is under development. After the necessary tests and improvements are made, it will be shared with the users as soon as possible.
None.
Built-in component themes created by the PrimeReact Theme Designer.
Premium themes are only available exclusively for PrimeReact Theme Designer subscribers and therefore not included in PrimeReact core.
Beautifully crafted premium create-react-app application templates by the PrimeTek design team.