Skip to content

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).

html
<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.
html
<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 icon field within a data object overrides the default icon.
html
<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).

html
<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).
html
<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.

html
<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.

html
<TuiTree :data="data" accordion />

Example: Editable Nodes

html
<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.

html
<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

html
<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

html
<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

html
<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.

html
<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

PropertyTypeDefaultDescription
dataArray[]Tree structure data.
nodeKeyString'id'Property name used as a unique identifier for each tree node.
propsObject-Configuration options: children, label, disabled, isLeaf, class.
emptyTextString-Text displayed when content is empty.
renderAfterExpandBooleantrueWhether to render child nodes only when first expanded.
highlightCurrentBooleanfalseWhether to highlight the currently selected node.
defaultExpandAllBooleanfalseWhether to expand all nodes by default.
expandOnClickNodeBooleantrueWhether to expand/collapse when the node is clicked. If false, it only expands when the arrow icon is clicked.
checkOnClickNodeBooleanfalseWhether to check the checkbox when the node is clicked.
autoExpandParentBooleantrueWhether to automatically expand parent nodes when a child node is expanded.
defaultExpandedKeysArray[]Array of keys of nodes to be expanded by default.
showCheckboxBooleanfalseWhether to display checkboxes.
checkStrictlyBooleanfalseWhether to strictly follow the non-linked parent-child relationship when checkboxes are displayed.
defaultCheckedKeysArray[]Array of keys of nodes to be checked by default.
currentNodeKeyString/Number-Key of the currently selected node.
filterNodeMethodFunction-Method executed when filtering tree nodes; returns true to display.
accordionBooleanfalseWhether to enable accordion mode.
indentNumber18Horizontal indentation between adjacent level nodes, in pixels.
iconString-Custom tree node icon (global default).
showIconBooleanfalseWhether to display node icons.
lazyBooleanfalseWhether to lazy load child nodes.
loadFunction-Method for loading sub-tree data.
draggableBooleanfalseWhether to enable node dragging functionality.
allowDragFunction-Determines if a node is allowed to be dragged.
allowDropFunction-Determines if a node can be dropped into.
appearanceString'tree'Appearance. Options: tree, menu, menu-block.

Events

Event NameDescriptionCallback Parameters
node-clickCallback when a node is clicked.(data, node, treeNodeEvent)
node-contextmenuTriggered when a node is right-clicked.(event, data, node, treeNodeEvent)
check-changeCallback when node check status changes.(data, checked, indeterminate)
checkTriggered after clicking a node checkbox.(data, { checkedNodes, checkedKeys, ... })
current-changeTriggered when the currently selected node changes.(data, node)
node-expandTriggered when a node is expanded.(data, node)
node-collapseTriggered when a node is collapsed.(data, node)
node-drag-startTriggered when node dragging starts.(node, event)
node-drag-enterTriggered when dragging enters another node.(draggingNode, dropNode, event)
node-drag-leaveTriggered when dragging leaves a node.(draggingNode, dropNode, event)
node-drag-overTriggered while dragging over a node (similar to mouseover).(draggingNode, dropNode, event)
node-drag-endTriggered when dragging ends (may not have successfully found a target node).(draggingNode, dropNode, dropType, event)
node-dropTriggered when a drag-and-drop operation is successfully completed.(draggingNode, dropNode, dropType, event)

Slots

Slot NameDescriptionParameters
defaultContent Slot. Customizes node content, overriding the default label display.{ node, data }
iconIcon Slot. Customizes the icon area on the left side of the node (requires showIcon to be enabled).{ node, data }

Exposed Methods

Method NameDescriptionParameters
filterFilters tree nodes.(value)
updateKeyChildrenSets child elements of a node via keys.(key, data)
getCheckedNodesReturns an array of currently checked nodes.(leafOnly, includeHalfChecked)
setCheckedNodesSets the currently checked nodes.(nodes)
getCheckedKeysReturns an array of keys of currently checked nodes.(leafOnly)
setCheckedKeysSets the currently checked nodes via keys.(keys, leafOnly)
setCheckedSets the check status of a node via key / data.(key/data, checked, deep)
getHalfCheckedNodesReturns an array of currently half-checked nodes.-
getHalfCheckedKeysReturns an array of keys of currently half-checked nodes.-
getCurrentKeyGets the key of the currently selected node.-
getCurrentNodeGets the data of the currently selected node.-
setCurrentKeySets the currently selected status of a node via key.(key)
setCurrentNodeSets the currently selected status of a node via node.(node)
getNodeRetrieves the Tree-node component based on data or key.(data)
removeDeletes a node.(data)
appendAdds a child node to a node.(data, parentNode)
insertBeforeInserts a node before the specified node.(data, refNode)
insertAfterInserts a node after the specified node.(data, refNode)

Released under the MIT License.