Tree
TuiTree is used to display data structures with hierarchical relationships. It supports various features such as multiple selection, filtering, and lazy loading, and provides extremely flexible node customization capabilities. It can be used to build file managers, organizational charts, or system menus.
Basic Usage
Basic Display
The simplest usage involves passing tree data via data and configuring option mapping via props (defaulting to label and children).
<script setup>
import { ref } from 'vue';
const treeData = ref([
{ id: 1, label: 'Level 1-1', children: [
{ id: 4, label: 'Level 2-1-1' }
]},
{ id: 2, label: 'Level 1-2', children: [
{ id: 5, label: 'Level 2-2-1' },
{ id: 6, label: 'Level 2-2-2' }
]}
]);
const defaultProps = { children: 'children', label: 'label' };
const handleNodeClick = (data) => console.log('Click:', data);
</script>
<template>
<TuiTree
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
/>
</template>Appearance Styles
TuiTree has three built-in appearance modes, which can be toggled via the appearance attribute.
- tree (Default): Standard tree structure with connecting lines.
- menu: Menu style without connecting lines and with more compact node spacing.
- menu-block: Block-level menu style where node backgrounds occupy the full row, featuring a hover highlight effect.
<template>
<TuiTree :data="data" appearance="menu" />
<TuiTree :data="data" appearance="menu-block" highlight-current />
</template>Icon Customization
Default and Node Icons
- showIcon: Whether to display icons (defaults to folder/file icons).
- icon: Sets the global default icon.
- Data Source Definition: Defining an
iconfield within a data object overrides the default icon.
<script setup>
const data = [
{ label: 'System Management', icon: 'tui-icon ti-settings' }, // Custom node icon
{ label: 'User List' } // Uses default icon
];
</script>
<template>
<TuiTree
showIcon
icon="tui-icon ti-file"
:data="data"
/>
</template>Scenario: File Management System
Using Scoped Slots, you can dynamically render different icons and styles based on node data (such as file type).
<template>
<TuiTree :data="fileData" default-expand-all>
<template #default="{ node, data }">
<div class="custom-tree-node">
<i :class="[
'tui-icon',
data.type === 'folder' ? (node.expanded ? 'tis-folder-open' : 'tis-folder') : 'ti-file'
]"></i>
<span>{{ data.label }}</span>
<span v-if="data.size" class="file-size">{{ data.size }}</span>
</div>
</template>
</TuiTree>
</template>Interactive Features
Multiple Selection (Checkbox)
Set show-checkbox to enable checkboxes.
default-checked-keys: An array of keys for nodes that are checked by default.check-strictly: Whether to strictly follow a non-linked parent-child relationship (selecting a parent does not automatically select children).
<script setup>
import { ref } from 'vue';
const treeRef = ref(null);
const getChecked = () => {
// Get an array of keys for checked nodes
console.log(treeRef.value.getCheckedKeys());
// Get full data for checked nodes
console.log(treeRef.value.getCheckedNodes());
};
</script>
<template>
<TuiTree
ref="treeRef"
:data="data"
show-checkbox
node-key="id"
:default-checked-keys="[5]"
/>
<TuiButton @click="getChecked">Get Checked</TuiButton>
</template>Node Filtering
Implement search functionality using the filter-node-method attribute and the filter method.
<script setup>
import { ref, watch } from 'vue';
const filterText = ref('');
const treeRef = ref(null);
// Filtering logic
const filterNode = (value, data, node) => {
if (!value) return true;
return node.label.includes(value);
};
watch(filterText, (val) => {
treeRef.value.filter(val);
});
</script>
<template>
<TuiInput v-model="filterText" placeholder="Enter keywords to filter" />
<TuiTree
ref="treeRef"
:data="data"
:filter-node-method="filterNode"
/>
</template>Accordion Mode
Set the accordion attribute so that only one node at the same level can be expanded at a time.
<TuiTree :data="data" accordion />Example: Editable Nodes
<template>
<TuiTree :data="data">
<template #default="{ node, data }">
<div class="custom-node">
<template v-if="data.isEditing">
<TuiInput v-model="data.label" size="small" />
<TuiButton link @click="save(data)">Save</TuiButton>
</template>
<template v-else>
<span>{{ data.label }}</span>
<TuiButton link @click="data.isEditing = true">Edit</TuiButton>
</template>
</div>
</template>
</TuiTree>
</template>Example: Organizational Chart
Combine Flex layout with custom styles to display information such as department headcounts.
<template #default="{ data }">
<div class="org-node">
<span class="org-icon">{{ data.icon }}</span>
<span class="org-name">{{ data.label }}</span>
<TuiTag size="small">{{ data.count }} people</TuiTag>
</div>
</template>Asynchronous Data Loading
For massive amounts of data, lazy loading mode can be used. Set lazy and load child nodes on demand via the load method.
Basic Lazy Loading
<script setup>
const loadNode = (node, resolve) => {
// level 0 represents the root node (if data is not provided in props)
if (node.level === 0) {
return resolve([{ name: 'Root 1' }, { name: 'Root 2' }]);
}
// Simulate asynchronous request
setTimeout(() => {
const data = [
{ name: 'leaf', leaf: true }, // leaf: true marks it as a leaf node
{ name: 'zone' }
];
resolve(data);
}, 500);
};
</script>
<template>
<TuiTree lazy :load="loadNode" :props="{ label: 'name', isLeaf: 'leaf' }" />
</template>Advanced Customization
TuiTree provides two core slots to meet different levels of customization needs.
Content Customization (#default)
The most commonly used slot. Used to customize the content of the entire node row. Parameters are { node, data }.
Example: File Management System
<template>
<TuiTree :data="fileData" default-expand-all>
<template #default="{ node, data }">
<div class="custom-tree-node file-node">
<span class="file-icon">
<i :class="['tui-icon', data.type === 'file' ? 'ti-file' : 'ti-folder']"></i>
</span>
<span class="file-name">{{ data.label }}</span>
<span v-if="data.size" class="file-size">{{ data.size }}</span>
<div class="actions" v-if="data.type === 'file'">
<TuiButton link size="small" @click.stop="download(data)">Download</TuiButton>
</div>
</div>
</template>
</TuiTree>
</template>Example: Organizational Chart
<template #default="{ data }">
<div class="org-node">
<span class="org-icon">{{ data.icon }}</span>
<span class="org-name">{{ data.label }}</span>
<TuiTag size="small">{{ data.count }} people</TuiTag>
</div>
</template>Icon Customization (#icon)
New Feature. If you only want to customize the expand/collapse arrow or the file icon without affecting the default rendering logic of the node text, you can use the #icon slot.
<TuiTree :data="data" show-icon>
<template #icon="{ node, data }">
<i v-if="node.loading" class="tui-icon ti-loader spin"></i>
<i v-else-if="node.isLeaf" class="tui-icon ti-file"></i>
<i v-else class="tui-icon ti-folder"></i>
</template>
</TuiTree>API Reference
Props
| Property | Type | Default | Description |
|---|---|---|---|
| data | Array | [] | Tree structure data. |
| nodeKey | String | 'id' | Property name used as a unique identifier for each tree node. |
| props | Object | - | Configuration options: children, label, disabled, isLeaf, class. |
| emptyText | String | - | Text displayed when content is empty. |
| renderAfterExpand | Boolean | true | Whether to render child nodes only when first expanded. |
| highlightCurrent | Boolean | false | Whether to highlight the currently selected node. |
| defaultExpandAll | Boolean | false | Whether to expand all nodes by default. |
| expandOnClickNode | Boolean | true | Whether to expand/collapse when the node is clicked. If false, it only expands when the arrow icon is clicked. |
| checkOnClickNode | Boolean | false | Whether to check the checkbox when the node is clicked. |
| autoExpandParent | Boolean | true | Whether to automatically expand parent nodes when a child node is expanded. |
| defaultExpandedKeys | Array | [] | Array of keys of nodes to be expanded by default. |
| showCheckbox | Boolean | false | Whether to display checkboxes. |
| checkStrictly | Boolean | false | Whether to strictly follow the non-linked parent-child relationship when checkboxes are displayed. |
| defaultCheckedKeys | Array | [] | Array of keys of nodes to be checked by default. |
| currentNodeKey | String/Number | - | Key of the currently selected node. |
| filterNodeMethod | Function | - | Method executed when filtering tree nodes; returns true to display. |
| accordion | Boolean | false | Whether to enable accordion mode. |
| indent | Number | 18 | Horizontal indentation between adjacent level nodes, in pixels. |
| icon | String | - | Custom tree node icon (global default). |
| showIcon | Boolean | false | Whether to display node icons. |
| lazy | Boolean | false | Whether to lazy load child nodes. |
| load | Function | - | Method for loading sub-tree data. |
| draggable | Boolean | false | Whether to enable node dragging functionality. |
| allowDrag | Function | - | Determines if a node is allowed to be dragged. |
| allowDrop | Function | - | Determines if a node can be dropped into. |
| appearance | String | 'tree' | Appearance. Options: tree, menu, menu-block. |
Events
| Event Name | Description | Callback Parameters |
|---|---|---|
| node-click | Callback when a node is clicked. | (data, node, treeNodeEvent) |
| node-contextmenu | Triggered when a node is right-clicked. | (event, data, node, treeNodeEvent) |
| check-change | Callback when node check status changes. | (data, checked, indeterminate) |
| check | Triggered after clicking a node checkbox. | (data, { checkedNodes, checkedKeys, ... }) |
| current-change | Triggered when the currently selected node changes. | (data, node) |
| node-expand | Triggered when a node is expanded. | (data, node) |
| node-collapse | Triggered when a node is collapsed. | (data, node) |
| node-drag-start | Triggered when node dragging starts. | (node, event) |
| node-drag-enter | Triggered when dragging enters another node. | (draggingNode, dropNode, event) |
| node-drag-leave | Triggered when dragging leaves a node. | (draggingNode, dropNode, event) |
| node-drag-over | Triggered while dragging over a node (similar to mouseover). | (draggingNode, dropNode, event) |
| node-drag-end | Triggered when dragging ends (may not have successfully found a target node). | (draggingNode, dropNode, dropType, event) |
| node-drop | Triggered when a drag-and-drop operation is successfully completed. | (draggingNode, dropNode, dropType, event) |
Slots
| Slot Name | Description | Parameters |
|---|---|---|
| default | Content Slot. Customizes node content, overriding the default label display. | { node, data } |
| icon | Icon Slot. Customizes the icon area on the left side of the node (requires showIcon to be enabled). | { node, data } |
Exposed Methods
| Method Name | Description | Parameters |
|---|---|---|
| filter | Filters tree nodes. | (value) |
| updateKeyChildren | Sets child elements of a node via keys. | (key, data) |
| getCheckedNodes | Returns an array of currently checked nodes. | (leafOnly, includeHalfChecked) |
| setCheckedNodes | Sets the currently checked nodes. | (nodes) |
| getCheckedKeys | Returns an array of keys of currently checked nodes. | (leafOnly) |
| setCheckedKeys | Sets the currently checked nodes via keys. | (keys, leafOnly) |
| setChecked | Sets the check status of a node via key / data. | (key/data, checked, deep) |
| getHalfCheckedNodes | Returns an array of currently half-checked nodes. | - |
| getHalfCheckedKeys | Returns an array of keys of currently half-checked nodes. | - |
| getCurrentKey | Gets the key of the currently selected node. | - |
| getCurrentNode | Gets the data of the currently selected node. | - |
| setCurrentKey | Sets the currently selected status of a node via key. | (key) |
| setCurrentNode | Sets the currently selected status of a node via node. | (node) |
| getNode | Retrieves the Tree-node component based on data or key. | (data) |
| remove | Deletes a node. | (data) |
| append | Adds a child node to a node. | (data, parentNode) |
| insertBefore | Inserts a node before the specified node. | (data, refNode) |
| insertAfter | Inserts a node after the specified node. | (data, refNode) |