Skip to content
Destyler UI Destyler UI Destyler UI

Tree

The Tree component provides a hierarchical view of data, similar to a file system explorer. It allows users to expand and collapse branches, select individual or multiple nodes, and traverse the hierarchy using keyboard navigation.

src
App.vue
main.ts
style.css
package.json
vite.config.ts
tsconfig.json
unocss.config.ts
README.md
package.json
vite.config.ts
tsconfig.json
unocss.config.ts
README.md
src
public
package.json
svelte.config.js
vite.config.ts
tsconfig.json
unocss.config.ts
README.md
package.json
vite.config.ts
tsconfig.json
unocss.config.ts
README.md

Features

Install

Install the component from your command line.

Terminal window
      
        
npm install @destyler/tree @destyler/vue
Terminal window
      
        
npm install @destyler/tree @destyler/react
Terminal window
      
        
npm install @destyler/tree @destyler/svelte
Terminal window
      
        
npm install @destyler/tree @destyler/solid

Anatomy

Import all parts and piece them together.

<script setup lang="ts">
import * as tree from '@destyler/tree'
import { normalizeProps, useMachine } from '@destyler/vue'
import { computed, useId } from 'vue'
import TreeNode from './Node.vue'
interface Node {
id: string
name: string
children?: Node[]
}
const collection = tree.collection<Node>({
nodeToValue: node => node.id,
nodeToString: node => node.name,
rootNode: {
id: 'ROOT',
name: '',
children: [
// ...
],
},
})
const [state, send] = useMachine(tree.machine({
id: useId(),
collection,
}))
const api = computed(() => tree.connect(state.value, send, normalizeProps))
</script>
<template>
<main>
<div v-bind="api.getRootProps()">
<div v-bind="api.getTreeProps()">
<TreeNode
v-for="(node, index) in api.collection.rootNode.children"
:key="node.id"
:node="node"
:index-path="[index]"
:api="api"
/>
</div>
</div>
</main>
</template>
import { normalizeProps, useMachine } from '@destyler/react'
import * as tree from '@destyler/tree'
import { useId } from 'react'
import TreeNode from './Node.tsx'
interface Node {
id: string
name: string
children?: Node[]
}
const collection = tree.collection<Node>({
nodeToValue: node => node.id,
nodeToString: node => node.name,
rootNode: {
id: 'ROOT',
name: '',
children: [
// ...
],
},
})
export default function Tree() {
const [state, send] = useMachine(tree.machine({
id: useId(),
collection,
}))
const api = tree.connect(state, send, normalizeProps)
return (
<main >
<div {...api.getRootProps()}>
<div {...api.getTreeProps()}>
{api.collection.rootNode.children?.map((node: any, index: any) => (
<TreeNode
key={node.id}
node={node}
indexPath={[index]}
api={api}
/>
))}
</div>
</div>
</main>
)
}
<script lang="ts">
import * as tree from '@destyler/tree'
import { normalizeProps, useMachine } from '@destyler/svelte'
import TreeNode from './Node.svelte'
interface Node {
id: string
name: string
children?: Node[]
}
const collection = tree.collection<Node>({
nodeToValue: node => node.id,
nodeToString: node => node.name,
rootNode: {
id: 'ROOT',
name: '',
children: [
// ...
],
},
})
const [state, send] = useMachine(tree.machine({
id: crypto.randomUUID(),
collection,
}))
const api = $derived(tree.connect(state, send, normalizeProps))
</script>
<main>
<div {...api.getRootProps()}>
<div {...api.getTreeProps()}>
{#each api.collection.rootNode.children as node, index}
<TreeNode
{node}
indexPath={[index]}
{api}
/>
{/each}
</div>
</div>
</main>
import { normalizeProps, useMachine } from '@destyler/solid'
import * as tree from '@destyler/tree'
import { createMemo, createUniqueId } from 'solid-js'
import TreeNode from './Node.tsx'
interface Node {
id: string
name: string
children?: Node[]
}
const collection = tree.collection<Node>({
nodeToValue: node => node.id,
nodeToString: node => node.name,
rootNode: {
id: 'ROOT',
name: '',
children: [
// ...
],
},
})
export default function Tree() {
const [state, send] = useMachine(tree.machine({
id: createUniqueId(),
collection,
}))
const api = createMemo(() => tree.connect(state, send, normalizeProps))
return (
<main>
<div {...api().getRootProps()}>
<div {...api().getTreeProps()}>
{api().collection.rootNode.children?.map((node: any, index: any) => (
<TreeNode
node={node}
indexPath={[index]}
api={api()}
/>
))}
</div>
</div>
</main>
)
}

Expanding and Collapsing Nodes

By default, the tree view will expand or collapse when clicking the branch control. To control the expanded state of the tree view, use the api.expand and api.collapse methods.

api.expand(["node_modules/unocss"]) // expand a single node
api.expand() // expand all nodes
api.collapse(["node_modules/unocss"]) // collapse a single node
api.collapse() // collapse all nodes

Multiple selection

The tree view supports multiple selection. To enable this, set the selectionMode to multiple.

const [state, send] = useMachine(
tree.machine({
selectionMode: "multiple",
}),
)

Setting the default expanded nodes

To set the default expanded nodes, use the expandedValue context property.

const [state, send] = useMachine(
tree.machine({
expandedValue: ["node_modules/unocss"],
}),
)

Setting the default selected nodes

To set the default selected nodes, use the selectedValue context property.

const [state, send] = useMachine(
tree.machine({
selectedValue: ["node_modules/unocss"],
}),
)

Listening for selection

When a node is selected, the onSelectionChange callback is invoked with the selected nodes.

const [state, send] = useMachine(
tree.machine({
onSelectionChange(details) {
console.log("selected nodes:", details)
},
}),
)

Listening for expanding and collapsing

When a node is expanded or collapsed, the onExpandedChange callback is invoked with the expanded nodes.

const [state, send] = useMachine(
tree.machine({
onExpandedChange(details) {
console.log("expanded nodes:", details)
},
}),
)

Methods and Properties

Machine Context

The tree machine exposes the following context properties:

collection
TreeCollection<T>
The tree collection data
ids
Partial<{ root: string; tree: string; label: string; node(value: string): string; }>
The ids of the tree elements. Useful for composition.
expandedValue
string[]
The id of the expanded nodes
selectedValue
string[]
The id of the selected nodes
focusedValue
string
The id of the focused node
selectionMode
"single" | "multiple"
Whether the tree supports multiple selection - "single": only one node can be selected - "multiple": multiple nodes can be selected
onExpandedChange
(details: ExpandedChangeDetails) => void
Called when the tree is opened or closed
onSelectionChange
(details: SelectionChangeDetails) => void
Called when the selection changes
onFocusChange
(details: FocusChangeDetails) => void
Called when the focused node changes
expandOnClick
boolean
Whether clicking on a branch should open it or not
typeahead
boolean
Whether the tree supports typeahead search
dir
"ltr" | "rtl"
The document's text/writing direction.
id
string
The unique identifier of the machine.
getRootNode
() => ShadowRoot | Node | Document
A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The tree api exposes the following methods:

collection
TreeCollection<V>
The tree collection data
expandedValue
string[]
The id of the expanded nodes
setExpandedValue
(value: string[]) => void
Function to set the expanded value
selectedValue
string[]
The id of the selected nodes
setSelectedValue
(value: string[]) => void
Function to set the selected value
getVisibleNodes
() => V[]
Function to get the visible nodes
expand
(value?: string[]) => void
Function to expand nodes. If no value is provided, all nodes will be expanded
collapse
(value?: string[]) => void
Function to collapse nodes If no value is provided, all nodes will be collapsed
select
(value?: string[]) => void
Function to select nodes If no value is provided, all nodes will be selected
deselect
(value?: string[]) => void
Function to deselect nodes If no value is provided, all nodes will be deselected
focus
(value: string) => void
Function to focus an item node
selectParent
(value: string) => void
Function to select the parent node of the focused node
expandParent
(value: string) => void
Function to expand the parent node of the focused node

Data Attributes

Item

name
desc
data-scope
tree-view
data-part
item
data-path
The path of the item
data-value
The value of the item
data-focus
Present when focused
data-selected
Present when selected
data-disabled
Present when disabled
data-depth
The depth of the item

Item Text

name
desc
data-scope
tree-view
data-part
item-text
data-disabled
Present when disabled
data-selected
Present when selected
data-focus
Present when focused

Item Indicator

name
desc
data-scope
tree-view
data-part
item-indicator
data-disabled
Present when disabled
data-selected
Present when selected
data-focus
Present when focused

Branch

name
desc
data-scope
tree-view
data-part
branch
data-depth
The depth of the item
data-value
The value of the item
data-path
The path of the item
data-selected
Present when selected
data-state
"open" | "closed"
data-disabled
Present when disabled

Branch Indicator

name
desc
data-scope
tree-view
data-part
branch-indicator
data-state
"open" | "closed"
data-disabled
Present when disabled
data-selected
Present when selected
data-focus
Present when focused

Branch Trigger

name
desc
data-scope
tree-view
data-part
branch-trigger
data-disabled
Present when disabled
data-state
"open" | "closed"
data-value
The value of the item

Branch Control

name
desc
data-scope
tree-view
data-part
branch-control
data-path
The path of the item
data-state
"open" | "closed"
data-disabled
Present when disabled
data-selected
Present when selected
data-focus
Present when focused
data-value
The value of the item
data-depth
The depth of the item

Branch Text

name
desc
data-scope
tree-view
data-part
branch-text
data-disabled
Present when disabled
data-state
"open" | "closed"

Branch Content

name
desc
data-scope
tree-view
data-part
branch-content
data-state
"open" | "closed"
data-depth
The depth of the item
data-path
The path of the item
data-value
The value of the item

Branch Indent Guide

name
desc
data-scope
tree-view
data-part
branch-indent-guide
data-depth
The depth of the item

Accessibility

Keyboard Interaction

name
desc
Tab
Moves focus to the tree view, placing the first tree view item in focus.
Enter
Selects the item or branch node
Space
Selects the item or branch node
ArrowDown
Moves focus to the next node
ArrowUp
Moves focus to the previous node
ArrowRight
When focus is on a closed branch node, opens the branch. When focus is on an open branch node, moves focus to the first item node.
ArrowLeft
When focus is on an open branch node, closes the node. When focus is on an item or branch node, moves focus to its parent branch node.
Home
Moves focus to first node without opening or closing a node.
End
Moves focus to the last node that can be focused without expanding any nodes that are closed.
a-z, A-Z
Focus moves to the next node with a name that starts with the typed character. The search logic ignores nodes that are descendants of closed branch.
*
Expands all sibling nodes that are at the same depth as the focused node.
Shift + ArrowDown
Moves focus to and toggles the selection state of the next node.
Shift + ArrowUp
Moves focus to and toggles the selection state of the previous node.
Ctrl + A
Selects all nodes in the tree. If all nodes are selected, unselects all nodes.