Skip to content

Migrating from ghl-ui DropdownTree to HighRise Dropdown (tree mode)

This guide helps you move from UIDropdownTree to HLDropdown with tree-mode enabled.

Component Implementation Changes

Import Changes

diff
- import { UIDropdownTree } from '@gohighlevel/ghl-ui'
+ import { HLDropdown, HLButton } from '@platform-ui/highrise'

Basic Usage Changes

diff
- <UIDropdownTree
-   v-model="selectedValue"
-   :options="options"
-   label="Select Option"
-   @on-select="handleSelect"
- />
+ <HLDropdown
+   id="tree-dropdown"
+   :options="options"
+   tree-mode
+   trigger="click"
+   placement="bottom-start"
+   :show-search="true"
+   @select="handleSelect"
+ >
+   <HLButton size="sm">Select Option</HLButton>
+ </HLDropdown>

Props Changes

ghl-ui PropHighRise Prop / PatternNotes
v-model@select + local stateHL emits select(key, option); manage selected value yourself.
optionsoptionsHLDropdownOption[] supports children for tree mode.
labelTrigger contentProvide button text/slot in the trigger.
placeholderTrigger contentSame as above.
idid (optional)Auto-generated if omitted.
triggertrigger'click' (default), 'hover', 'focus'.
placementplacementDefault bottom-start; RTL-aware.
widthwidthNumber or 'auto'; default 182.
tree-modetree-modeEnables hierarchical navigation.
show-searchshow-searchBuilt-in search row (default true).
-closeOnSelectClose after selection (default true).
-multipleMulti-select support (default false).
-searchValue / @update:searchValueControl search input if needed.

Options Format (tree)

Use the same HLDropdownOption shape as standard dropdowns, with children arrays for nesting.

Examples

Basic Tree Dropdown

vue
<template>
  <HLDropdown id="basic-tree" :options="options" tree-mode :show-search="true" :width="240">
    <HLButton size="sm">Choose location</HLButton>
  </HLDropdown>
</template>

<script setup>
const options = [
  {
    key: 'locations',
    label: 'Locations',
    children: [
      { key: 'usa', label: 'USA' },
      { key: 'india', label: 'India' },
    ],
  },
]
</script>

Tree Dropdown with Form Validation

vue
<template>
  <HLForm :model="form" :rules="rules">
    <HLFormItem label="Category" path="category" required>
      <HLDropdown id="category-dropdown" :options="categories" tree-mode :show-search="true" :width="260" @select="handleSelect">
        <HLButton size="sm">{{ form.category || 'Select Category' }}</HLButton>
      </HLDropdown>
    </HLFormItem>
  </HLForm>
</template>

<script setup>
import { reactive } from 'vue'

const form = reactive({ category: '' })
const categories = [
  { key: 'fruits', label: 'Fruits', children: [{ key: 'apple', label: 'Apple' }] },
  { key: 'vegetables', label: 'Vegetables', children: [{ key: 'carrot', label: 'Carrot' }] },
]

const handleSelect = (key, option) => {
  form.category = option.label
}

const rules = {
  category: [{ required: true, message: 'Please select a category', trigger: 'change' }],
}
</script>

Custom Search Handling

vue
<template>
  <HLDropdown id="custom-search-tree" :options="filteredOptions" tree-mode :show-search="true" :width="260" @search="handleSearch">
    <HLButton size="sm">Custom Search</HLButton>
  </HLDropdown>
</template>

<script setup>
import { computed, ref } from 'vue'

const search = ref('')
const allOptions = [
  {
    key: 'colors',
    label: 'Colors',
    children: [
      { key: 'red', label: 'Red' },
      { key: 'blue', label: 'Blue' },
    ],
  },
]

const filteredOptions = computed(() => {
  if (!search.value) return allOptions
  const term = search.value.toLowerCase()
  return allOptions
    .map(group => {
      const children = group.children?.filter(item => item.label.toLowerCase().includes(term))
      return children?.length ? { ...group, children } : null
    })
    .filter(Boolean)
})

const handleSearch = value => {
  search.value = value
}
</script>

Best Practices

  1. Provide an explicit id when tests need deterministic selectors.
  2. Keep option keys stable; tree navigation relies on them.
  3. Use showSearch for discoverability; disable when the tree is small.
  4. Combine multiple with showSelectedMark for multi-select scenarios.
  5. Consider width='auto' to match trigger width when embedding in tight layouts.