TreeSelect
TreeSelect is a dropdown for picking from a tree. The model is the flat list of selected leaf keys (by default), and parent nodes render a derived checked/indeterminate state. It shows the selection as Tags in the trigger and supports filtering.
vue
<script setup lang="ts">
import { ref } from 'vue'
import { TreeSelect, type TreeNode } from '@myghf/ui'
const selected = ref<string[]>([])
const nodes: TreeNode[] = [
{
value: 'cardiology',
label: 'Cardiology',
children: [
{ value: 'echo', label: 'Echocardiography' },
{ value: 'ecg', label: 'ECG' },
],
},
]
</script>
<template>
<TreeSelect v-model="selected" :nodes="nodes" />
</template>Examples
Selecting leaf services
Selecting a parent selects all of its leaves, and a partially selected parent shows an indeterminate marker. The emitted value is always a flat array of leaf keys; a Clear action appears while anything is selected.
Selected leaf keys: echo
vue
<script setup lang="ts">
import { ref } from 'vue'
import { TreeSelect, type TreeNode } from '@myghf/ui'
const selected = ref<string[]>(['echo'])
const nodes: TreeNode[] = [
{
value: 'cardiology',
label: 'Cardiology',
children: [
{ value: 'echo', label: 'Echocardiography' },
{ value: 'ecg', label: 'ECG' },
],
},
{ value: 'radiology', label: 'Radiology' },
{ value: 'mri', label: 'MRI' },
]
</script>
<template>
<div class="max-w-sm">
<TreeSelect v-model="selected" :nodes="nodes" placeholder="Choose services" />
<p class="mt-3 text-sm text-muted">
Selected leaf keys: {{ selected.join(', ') || 'none' }}
</p>
</div>
</template>Node shape
Each node is a TreeNode<T>:
ts
interface TreeNode<T = unknown> {
value: string // stable key; the value emitted by TreeSelect
label?: string // shown in the tree and the trigger tags
disabled?: boolean // present in the type, but not currently enforced
children?: TreeNode<T>[]
data?: T
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string[] | [] | Selected leaf keys. |
nodes | TreeNode<T>[] | — (required) | The tree. |
placeholder | string | 'Select' | Trigger text when nothing is selected. |
filterable | boolean | true | Shows a search input above the tree. |
filterPlaceholder | string | 'Search' | Placeholder for the search input. |
disabled | boolean | false | Disables the trigger and the popup. |
leafOnly | boolean | true | Emits only leaf keys, so parent groups are not selectable values. Set false to emit parent keys too. |
size | 'sm' | 'default' | 'default' | Trigger height. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | string[] | Emitted with the flat list of selected keys. Clear emits []. |
Slots
TreeSelect renders no slots. Node content is limited to label / value.
Exposed methods
None. TreeSelect does not call defineExpose.
Accessibility
- The trigger is a
<button>; the popup is a reka-uiTree(role="tree"/treeitem) in multiple, bubble-select mode, so keyboard navigation and selection follow the tree pattern. The search input is a native<input>. - The checkbox squares are
aria-hiddenspans; selection state comes from the tree item, so assistive technology is not double-announcing. Give the trigger a name through its visible placeholder/tags, or addaria-labelin your layout. TreeNode.disabledis part of the type but is not passed to the tree items, so marked nodes remain selectable. Treat it as reserved.- There is no
invalidprop and noaria-invalidwiring.
Dark mode & RTL
- The trigger, popup, search field, and tags use semantic tokens (
bg-surface,text-foreground,border-border,surface-muted), so both themes adapt automatically. Selected-node rows usebg-primary-500with white marks. - Indentation uses
paddingInlineStart, so nesting mirrors under RTL, and the search icon is positioned withstart-2while the input reserves space withps-7. No physical directional utilities are used.