Skip to content

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 ​

PropTypeDefaultDescription
modelValuestring[][]Selected leaf keys.
nodesTreeNode<T>[]— (required)The tree.
placeholderstring'Select'Trigger text when nothing is selected.
filterablebooleantrueShows a search input above the tree.
filterPlaceholderstring'Search'Placeholder for the search input.
disabledbooleanfalseDisables the trigger and the popup.
leafOnlybooleantrueEmits only leaf keys, so parent groups are not selectable values. Set false to emit parent keys too.
size'sm' | 'default''default'Trigger height.

Events ​

EventPayloadDescription
update:modelValuestring[]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-ui Tree (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-hidden spans; 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 add aria-label in your layout.
  • TreeNode.disabled is part of the type but is not passed to the tree items, so marked nodes remain selectable. Treat it as reserved.
  • There is no invalid prop and no aria-invalid wiring.

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 use bg-primary-500 with white marks.
  • Indentation uses paddingInlineStart, so nesting mirrors under RTL, and the search icon is positioned with start-2 while the input reserves space with ps-7. No physical directional utilities are used.

Released under the MIT License.