Migrating from ghl-ui DropdownTree to HighRise Dropdown
This guide will help you migrate from the ghl-ui DropdownTree component to the new HighRise Dropdown component with tree mode.
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"
+ trigger="click"
+ placement="bottom"
+ :options="options"
+ tree-mode
+ show-search
+ @select="handleSelect"
+ :width="280"
+ >
+ <HLButton size="sm">Select Option</HLButton>
+ </HLDropdown>
Props Changes
ghl-ui Prop | HighRise Prop | Notes |
---|---|---|
v-model | @select event | Changed to event-based selection |
options | options | Enhanced option structure |
label | Button text | Moved to trigger button |
placeholder | Button text | Moved to trigger button |
id | id | Required for accessibility |
trigger | trigger | New prop for trigger type |
placement | placement | New prop for dropdown position |
width | width | New prop for dropdown width |
tree-mode | tree-mode | New prop for tree structure |
show-search | show-search | New prop for search functionality |
Examples
Basic Tree Dropdown
vue
<template>
<HLDropdown id="basic-tree-dropdown" trigger="click" placement="bottom" :options="options" tree-mode show-search :width="280">
<HLButton size="sm">Basic Tree Dropdown</HLButton>
</HLDropdown>
</template>
<script setup>
import { HLDropdown, HLButton } from '@platform-ui/highrise'
const options = [
{
key: 'locations',
label: 'Locations',
children: [
{
key: 'usa',
label: 'USA',
type: 'avatar',
src: 'path/to/usa-flag.png',
infoText: '+1',
},
{
key: 'india',
label: 'India',
type: 'avatar',
src: 'path/to/india-flag.png',
infoText: '+91',
},
],
},
]
</script>
Tree Dropdown with Validation
vue
<template>
<HLForm :model="formModel" :rules="rules">
<HLFormItem label="Category" path="category" required>
<HLDropdown
id="category-dropdown"
trigger="click"
placement="bottom"
:options="categories"
tree-mode
show-search
:width="280"
@select="handleSelect"
>
<HLButton size="sm">
{{ formModel.category || 'Select Category' }}
</HLButton>
</HLDropdown>
</HLFormItem>
</HLForm>
</template>
<script setup>
import { ref } from 'vue'
import { HLForm, HLFormItem, HLDropdown, HLButton } from '@platform-ui/highrise'
const formModel = ref({
category: '',
})
const categories = [
{
key: 'fruits',
label: 'Fruits',
children: [
{ key: 'apple', label: 'Apple', description: 'Red and sweet' },
{ key: 'banana', label: 'Banana', description: 'Yellow and creamy' },
{ key: 'orange', label: 'Orange', description: 'Citrus fruit' },
],
},
{
key: 'vegetables',
label: 'Vegetables',
children: [
{ key: 'carrot', label: 'Carrot', description: 'Orange and crunchy' },
{ key: 'broccoli', label: 'Broccoli', description: 'Green and healthy' },
{ key: 'potato', label: 'Potato', description: 'Starchy vegetable' },
],
},
]
const handleSelect = (key, option) => {
formModel.value.category = option.label
}
const rules = {
category: [
{
required: true,
message: 'Please select a category',
trigger: 'change',
},
],
}
</script>
Tree Dropdown with Custom Search
vue
<template>
<HLDropdown
id="custom-search-dropdown"
trigger="click"
placement="bottom"
:options="filteredOptions"
tree-mode
show-search
:width="280"
@search="handleSearch"
>
<HLButton size="sm">Custom Search</HLButton>
</HLDropdown>
</template>
<script setup>
import { ref, computed } from 'vue'
import { HLDropdown, HLButton } from '@platform-ui/highrise'
const searchQuery = ref('')
const isLoading = ref(false)
const allOptions = [
{
key: 'fruits',
label: 'Fruits',
children: [
{ key: 'apple', label: 'Apple', description: 'Red and sweet' },
{ key: 'banana', label: 'Banana', description: 'Yellow and creamy' },
{ key: 'orange', label: 'Orange', description: 'Citrus fruit' },
],
},
{
key: 'vegetables',
label: 'Vegetables',
children: [
{ key: 'carrot', label: 'Carrot', description: 'Orange and crunchy' },
{ key: 'broccoli', label: 'Broccoli', description: 'Green and healthy' },
{ key: 'potato', label: 'Potato', description: 'Starchy vegetable' },
],
},
]
const filteredOptions = computed(() => {
if (!searchQuery.value) return allOptions
const searchLower = searchQuery.value.toLowerCase()
return allOptions
.map(group => {
const matchingChildren = group.children?.filter(
item => item.label.toLowerCase().includes(searchLower) || item.description?.toLowerCase().includes(searchLower)
)
if (!matchingChildren?.length) return null
return {
...group,
children: matchingChildren,
}
})
.filter(Boolean)
})
let searchTimeout
const handleSearch = value => {
clearTimeout(searchTimeout)
isLoading.value = true
searchTimeout = setTimeout(() => {
searchQuery.value = value
isLoading.value = false
}, 300)
}
</script>
Best Practices
- Always provide a unique
id
for accessibility - Use appropriate trigger type for your use case
- Implement proper form validation
- Consider dropdown placement
- Handle search functionality appropriately
- Add proper ARIA labels
- Handle loading states appropriately
- Use descriptive labels
- Implement proper error handling
- Consider using tooltips for additional information
- Handle disabled states properly
- Use consistent spacing and alignment
- Consider option grouping
- Handle nested options appropriately
- Use appropriate icons and avatars
- Consider search performance
Additional Notes
- The component automatically handles focus states
- Error states are managed through validation status
- Supports keyboard navigation
- Maintains consistent styling with other form components
- Handles disabled states consistently
- Integrates seamlessly with form validation
- Maintains accessibility standards
- Supports custom styling through CSS variables
- Provides clear visual feedback for all states
- Works well on both desktop and mobile devices
- Supports both controlled and uncontrolled modes
- Includes built-in validation support
- Supports custom option rendering
- Handles option selection and deselection
- Supports custom search implementation
- Provides clear option validation
- Supports option grouping
- Handles nested navigation