Dropdown
A highly customizable and extensible dropdown component that supports flat lists, nested tree navigation, search, selection states, and rich option rendering.
Basic Dropdown
The basic dropdown component provides a way to display a list of selectable options in a popup menu. It expects the trigger element to be the default slot.
Here's a simple dropdown with click trigger and basic options:
<template>
<HLDropdown
id="basic-dropdown"
trigger="click"
placement="bottom"
:options="simpleOptions"
:show-search="false"
width="200"
@select="handleSelect"
>
<HLButton size="sm">Basic Dropdown</HLButton>
</HLDropdown>
</template>// Define your options - each must have a unique key and label
const simpleOptions = [
{
key: 'edit',
label: 'Edit Document',
},
{
key: 'share',
label: 'Share with Team',
},
{
key: 'download',
label: 'Download as PDF',
},
{
key: 'duplicate',
label: 'Make a Copy',
},
{
key: 'archive',
label: 'Archive Document',
},
{
key: 'delete',
label: 'Delete Document',
},
]1. Trigger Types
Choose how users activate the dropdown:
<!-- Click Trigger (Default) -->
<HLDropdown trigger="click" :options="simpleOptions" :show-search="false">
<HLButton>Click Me</HLButton>
</HLDropdown>
<!-- Hover Trigger -->
<HLDropdown trigger="hover" :options="simpleOptions" :show-search="false">
<HLButton>Hover Me</HLButton>
</HLDropdown>
<!-- Focus Trigger -->
<HLDropdown trigger="focus" :options="simpleOptions" :show-search="false">
<HLButton>Focus Me</HLButton>
</HLDropdown>// Define your options - each must have a unique key and label
const simpleOptions = [
{
key: 'edit',
label: 'Edit Document',
},
{
key: 'share',
label: 'Share with Team',
},
{
key: 'download',
label: 'Download as PDF',
},
{
key: 'duplicate',
label: 'Make a Copy',
},
{
key: 'archive',
label: 'Archive Document',
},
{
key: 'delete',
label: 'Delete Document',
},
]2. Placement Options
Position your dropdown relative to the trigger element in any of the following directions: top-start, top, top-end, right-start, right, right-end, bottom-start, bottom, bottom-end, left-start, left, left-end
<!-- Different placement examples -->
<HLDropdown id="placement-demo-1" placement="top-start" :options="simpleOptions" :show-search="false" width="200">
<HLButton size="sm">Opens Top Start</HLButton>
</HLDropdown>
<HLDropdown id="placement-demo-2" placement="bottom-end" :options="simpleOptions" :show-search="false" width="200">
<HLButton size="sm">Opens Bottom End</HLButton>
</HLDropdown>
<HLDropdown id="placement-demo-3" placement="right" :options="simpleOptions" :show-search="false" width="200">
<HLButton size="sm">Opens Right</HLButton>
</HLDropdown>// Define your options - each must have a unique key and label
const simpleOptions = [
{
key: 'edit',
label: 'Edit Document',
},
{
key: 'share',
label: 'Share with Team',
},
{
key: 'download',
label: 'Download as PDF',
},
{
key: 'duplicate',
label: 'Make a Copy',
},
{
key: 'archive',
label: 'Archive Document',
},
{
key: 'delete',
label: 'Delete Document',
},
]3. Width Control
Adapt the dropdown width to your content:
<!-- Fixed width -->
<HLDropdown id="width-demo-1" :width="200" :options="simpleOptions" :show-search="false">
<HLButton size="sm">Fixed 200px Width</HLButton>
</HLDropdown>
<!-- Auto width (matches trigger width) -->
<HLDropdown id="width-demo-2" width="auto" :options="simpleOptions" :show-search="false">
<HLButton size="sm" class="w-[200px]">Auto Width</HLButton>
</HLDropdown>// Define your options - each must have a unique key and label
const simpleOptions = [
{
key: 'edit',
label: 'Edit Document',
},
{
key: 'share',
label: 'Share with Team',
},
{
key: 'download',
label: 'Download as PDF',
},
{
key: 'duplicate',
label: 'Make a Copy',
},
{
key: 'archive',
label: 'Archive Document',
},
{
key: 'delete',
label: 'Delete Document',
},
]Nested Options
The dropdown component supports nested options, which can be displayed in either a hierarchical cascade or a tree structure.
1. Cascading Dropdown
A cascading dropdown displays options in a linear sequence, where each option's children are displayed as a new dropdown.
<HLDropdown id="nested-dropdown" trigger="click" placement="bottom" :options="nestedOptions" width="200">
<HLButton size="sm">Nested Dropdown</HLButton>
</HLDropdown>const nestedOptions = [
{
key: 'produce',
label: 'Fresh Produce',
children: [
{
key: 'fruits',
label: 'Fruits & Berries',
children: [
{
key: 'tropical',
label: 'Tropical Fruits',
children: [
{ key: 'mango', label: 'Mango', description: 'Sweet and juicy' },
{ key: 'pineapple', label: 'Pineapple', description: 'Tangy and tropical' },
{ key: 'papaya', label: 'Papaya', description: 'Soft and sweet' },
],
},
{
key: 'berries',
label: 'Fresh Berries',
children: [
{ key: 'strawberry', label: 'Strawberry', description: 'Red and fragrant' },
{ key: 'blueberry', label: 'Blueberry', description: 'Small and antioxidant-rich' },
{ key: 'raspberry', label: 'Raspberry', description: 'Tart and delicate' },
],
},
],
},
{
key: 'vegetables',
label: 'Vegetables',
children: [
{
key: 'leafy',
label: 'Leafy Greens',
children: [
{ key: 'spinach', label: 'Spinach', description: 'Dark and nutritious' },
{ key: 'kale', label: 'Kale', description: 'Crispy and healthy' },
{ key: 'lettuce', label: 'Lettuce', description: 'Fresh and crisp' },
],
},
{
key: 'root',
label: 'Root Vegetables',
children: [
{ key: 'carrot', label: 'Carrot', description: 'Orange and crunchy' },
{ key: 'potato', label: 'Potato', description: 'Starchy and versatile' },
{ key: 'beet', label: 'Beet', description: 'Deep red and earthy' },
],
},
],
},
],
},
{
key: 'dairy',
label: 'Dairy & Eggs',
children: [
{
key: 'milk_products',
label: 'Milk Products',
children: [
{
key: 'fresh_milk',
label: 'Fresh Milk',
children: [
{ key: 'whole_milk', label: 'Whole Milk', description: 'Full fat and creamy' },
{ key: 'reduced_fat', label: '2% Milk', description: 'Reduced fat option' },
{ key: 'skim_milk', label: 'Skim Milk', description: 'Fat-free option' },
],
},
{
key: 'yogurt',
label: 'Yogurt',
children: [
{ key: 'greek', label: 'Greek Yogurt', description: 'Thick and protein-rich' },
{ key: 'regular', label: 'Regular Yogurt', description: 'Smooth and creamy' },
{ key: 'probiotic', label: 'Probiotic Yogurt', description: 'With live cultures' },
],
},
],
},
{
key: 'cheese',
label: 'Cheese',
children: [
{
key: 'hard_cheese',
label: 'Hard Cheese',
children: [
{ key: 'cheddar', label: 'Cheddar', description: 'Sharp and aged' },
{ key: 'parmesan', label: 'Parmesan', description: 'Granular and salty' },
{ key: 'gouda', label: 'Gouda', description: 'Rich and smooth' },
],
},
{
key: 'soft_cheese',
label: 'Soft Cheese',
children: [
{ key: 'brie', label: 'Brie', description: 'Creamy and mild' },
{ key: 'mozzarella', label: 'Mozzarella', description: 'Fresh and milky' },
{ key: 'camembert', label: 'Camembert', description: 'Rich and buttery' },
],
},
],
},
],
},
]2. Dropdown Tree
The same options can be displayed in a nested tree structure, which enables hierarchical navigation:
<template>
<HLDropdown id="tree-dropdown" trigger="click" placement="bottom" :options="nestedOptions" tree-mode show-search :width="280">
<HLButton size="sm">Dropdown Tree</HLButton>
</HLDropdown>
</template>const nestedOptions = [
{
key: 'produce',
label: 'Fresh Produce',
children: [
{
key: 'fruits',
label: 'Fruits & Berries',
children: [
{
key: 'tropical',
label: 'Tropical Fruits',
children: [
{ key: 'mango', label: 'Mango', description: 'Sweet and juicy' },
{ key: 'pineapple', label: 'Pineapple', description: 'Tangy and tropical' },
{ key: 'papaya', label: 'Papaya', description: 'Soft and sweet' },
],
},
{
key: 'berries',
label: 'Fresh Berries',
children: [
{ key: 'strawberry', label: 'Strawberry', description: 'Red and fragrant' },
{ key: 'blueberry', label: 'Blueberry', description: 'Small and antioxidant-rich' },
{ key: 'raspberry', label: 'Raspberry', description: 'Tart and delicate' },
],
},
],
},
{
key: 'vegetables',
label: 'Vegetables',
children: [
{
key: 'leafy',
label: 'Leafy Greens',
children: [
{ key: 'spinach', label: 'Spinach', description: 'Dark and nutritious' },
{ key: 'kale', label: 'Kale', description: 'Crispy and healthy' },
{ key: 'lettuce', label: 'Lettuce', description: 'Fresh and crisp' },
],
},
{
key: 'root',
label: 'Root Vegetables',
children: [
{ key: 'carrot', label: 'Carrot', description: 'Orange and crunchy' },
{ key: 'potato', label: 'Potato', description: 'Starchy and versatile' },
{ key: 'beet', label: 'Beet', description: 'Deep red and earthy' },
],
},
],
},
],
},
{
key: 'dairy',
label: 'Dairy & Eggs',
children: [
{
key: 'milk_products',
label: 'Milk Products',
children: [
{
key: 'fresh_milk',
label: 'Fresh Milk',
children: [
{ key: 'whole_milk', label: 'Whole Milk', description: 'Full fat and creamy' },
{ key: 'reduced_fat', label: '2% Milk', description: 'Reduced fat option' },
{ key: 'skim_milk', label: 'Skim Milk', description: 'Fat-free option' },
],
},
{
key: 'yogurt',
label: 'Yogurt',
children: [
{ key: 'greek', label: 'Greek Yogurt', description: 'Thick and protein-rich' },
{ key: 'regular', label: 'Regular Yogurt', description: 'Smooth and creamy' },
{ key: 'probiotic', label: 'Probiotic Yogurt', description: 'With live cultures' },
],
},
],
},
{
key: 'cheese',
label: 'Cheese',
children: [
{
key: 'hard_cheese',
label: 'Hard Cheese',
children: [
{ key: 'cheddar', label: 'Cheddar', description: 'Sharp and aged' },
{ key: 'parmesan', label: 'Parmesan', description: 'Granular and salty' },
{ key: 'gouda', label: 'Gouda', description: 'Rich and smooth' },
],
},
{
key: 'soft_cheese',
label: 'Soft Cheese',
children: [
{ key: 'brie', label: 'Brie', description: 'Creamy and mild' },
{ key: 'mozzarella', label: 'Mozzarella', description: 'Fresh and milky' },
{ key: 'camembert', label: 'Camembert', description: 'Rich and buttery' },
],
},
],
},
],
},
]Basic search
The dropdown component includes a built-in search functionality that is enabled by default (show-search prop defaults to true). The search feature:
- Filters through leaf nodes (options without children) in both flat and nested structures
- Matches case-insensitive text against the option's
labelproperty - Displays the full path for nested options (e.g., "Parent / Child")
- Can be disabled by setting
show-searchtofalse
For custom search implementation, you can:
- Use the
onSearchprop to provide a custom search handler function - Listen to the
@searchevent to implement your own search logic
<HLDropdown id="basic-dropdown" trigger="click" placement="bottom" :options="longOptions" width="200" show-search>
<HLButton size="sm">Basic Dropdown with Search</HLButton>
</HLDropdown>Custom Search
The dropdown component allows you to implement custom search functionality by handling the @search event. This is useful when you need to perform server-side filtering or apply complex search logic.
<template>
<HLDropdown
id="custom-search-dropdown"
trigger="click"
placement="bottom"
:options="filteredOptions"
show-search
:width="280"
@search="handleSearch"
>
<HLButton size="sm">Custom Search</HLButton>
</HLDropdown>
</template>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)
}Height Limitation
The maxHeight prop can be used to limit the height of the dropdown. It is only applicable when treeMode is enabled.
<HLDropdown
id="tree-dropdown"
trigger="click"
placement="bottom"
:options="longOptions"
tree-mode
show-search
max-height="200px"
:width="280"
>
<HLButton size="sm">Dropdown Tree</HLButton>
</HLDropdown>Option Types
The dropdown component supports various option types, each designed for specific use cases. Below is a concise overview of each type with examples:
Default Text Option - Simple text options with a key and a label.
ts{ key: 'default', label: 'Default Option' }Header - Used to group options together.
ts{ key: 'header1', label: 'Group 1', type: 'header' }Divider - Used to separate options.
ts{ key: 'divider1', type: 'divider' }Avatar - Displays an image.
ts{ key: 'avatar1', label: 'User Profile', type: 'avatar', src: 'https://ui-avatars.com/api/?name=John+Doe' }Icon - Displays an icon. You can also set
iconPlacementto place the icon on either side of the label. Note that if you have children, the icon will be placed on the left side by default to accomodate the chevron icon for the children.ts{ key: 'icon1', label: 'Verified Account', type: 'icon', icon: CheckVerified01Icon, iconPlacement: 'left' }Description with Icon - Displays a description with an icon
ts{ key: 'desc1', label: 'Share Post', description: 'Share to social media channels', descriptionIcon: CheckVerified01Icon }Info Text - Displays additional text to the right of the label
ts{ key: 'info1', label: 'Messages', infoText: '5 unread' }Title Right Slot - Displays custom content on the right side
ts{ key: 'slot1', label: 'Performance', titleRightSlot: () => h(HLTag, { size: 'xs', round: true, variant: 'success' }, { default: () => '↑ 10%' }) }Disabled - Disables an option
ts{ key: 'disabled1', label: 'Unavailable Feature', disabled: true }Search: Displays a search input
ts{ key: '__search__', label: 'Search', type: 'search', searchPlaceholder: 'Search options...' }
<template>
<HLDropdown :options="demoOptions" showSearch treeMode showSelectedMark :closeOnSelect="false" @select="handleDemoSelect">
<HLButton>{{ demoSelectedValue }}</HLButton>
</HLDropdown>
</template>
<script setup>
import { CheckVerified01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { h } from 'vue'
import { HLTag } from '@gohighlevel/highrise'
const options = [
// Default option
{
key: 'default',
label: 'Default Option',
},
// Header option
{
key: 'header1',
label: 'Group 1',
type: 'header',
},
// Divider
{
key: 'divider1',
type: 'divider',
},
// Avatar option
{
key: 'avatar1',
label: 'User Profile',
type: 'avatar',
src: 'https://example.com/avatar.jpg',
},
// Icon option with left placement
{
key: 'icon1',
label: 'Verified Account',
type: 'icon',
icon: CheckVerified01Icon,
iconPlacement: 'left',
},
// Custom render option
{
key: 'render1',
type: 'render',
render: () => h('div', { class: 'custom-render' }, 'Custom Rendered Content'),
},
// Option with description and icon
{
key: 'desc1',
label: 'Share Post',
description: 'Share to social media channels',
descriptionIcon: CheckVerified01Icon,
},
// Option with info text
{
key: 'info1',
label: 'Messages',
infoText: '5 unread',
},
// Option with title right slot
{
key: 'slot1',
label: 'Performance',
titleRightSlot: () => h(HLTag, { size: 'xs', round: true, variant: 'success' }, { default: () => '↑ 10%' }),
},
// Disabled option
{
key: 'disabled1',
label: 'Unavailable Feature',
disabled: true,
},
// Nested options (children)
{
key: 'parent1',
label: 'Settings',
children: [
{
key: 'child1',
label: 'General',
},
{
key: 'child2',
label: 'Security',
},
],
},
]
</script>Scroll Event
Event @scroll is supported in the dropdown component only when we set max-height and treeMode.
<template>
<HLDropdown :options="InfiniteScrollOptions" @scroll="handleScroll" max-height="200px">
<HLButton size="sm">With Scroll Event</HLButton>
</HLDropdown>
</template>
<script setup>
import { HLDropdown, HLButton } from '@platform-ui/highrise'
import { ref } from 'vue'
const handleScroll = async event => {
const scrollPosition = event.target.scrollTop + event.target.clientHeight
if (scrollPosition >= event.target.scrollHeight - 10) {
const result = await fetchOptions() // fetch API
InfiniteScrollOptions.value = [...InfiniteScrollOptions.value, ...result]
}
}
const InfiniteScrollOptions = ref([
{
label: 'Option 1',
key: 'option1',
},
{
label: 'Option 2',
key: 'option2',
},
])
</script>Custom Render
The dropdown component supports custom rendering of options using the render type. This is useful for creating highly customized option displays:
WARNING
The @select event is not supported in the render type. You might want to add click handlers to the custom rendered content to handle the selection.
<template>
<HLDropdown id="custom-render-dropdown" trigger="click" placement="bottom" :options="options">
<HLButton size="sm">Custom Render</HLButton>
</HLDropdown>
</template>const options = [
{
key: 'complex-custom-content',
label: 'Complex Custom Content',
type: 'render',
render: () => h('div', { class: 'flex flex-col gap-2 p-2' }, [
h('div', { class: 'flex items-center gap-2' }, [
h('img', {
src: 'https://ui-avatars.com/api/?name=John+Doe',
class: 'w-8 h-8 rounded-full',
alt: 'Avatar',
}),
h('div', { class: 'text-sm font-medium' }, 'John Doe'),
]),
h('div', { class: 'text-xs text-gray-500' }, 'This is a more complex custom rendered option'),
h('div', { class: 'mt-2 flex items-center gap-2' }, [
h('div', { class: 'w-2 h-2 rounded-full bg-green-500' }),
h('span', { class: 'text-xs' }, 'Active'),
h(HLTag, { size: 'xs', round: true, variant: 'info' }, { default: () => 'New' }),
]),
])
},
{
key: 'notification',
label: 'Notification Item',
type: 'render',
render: () => h('div', { class: 'flex items-center justify-between p-2 border-b border-gray-100' }, [
h('div', { class: 'flex items-center gap-3' }, [
h('div', { class: 'w-2 h-2 rounded-full bg-error-500' }),
h('div', { class: 'flex flex-col' }, [
h('div', { class: 'text-sm font-medium' }, 'System Alert'),
h('div', { class: 'text-xs text-gray-500' }, '2 minutes ago')
])
]),
h(HLTag, { size: 'xs', variant: 'error' }, { default: () => 'Urgent' })
])
},
{
key: 'user-stats',
label: 'User Statistics',
type: 'render',
render: () => h('div', { class: 'p-2 flex flex-col gap-2' }, [
h('div', { class: 'flex items-center justify-between' }, [
h('div', { class: 'text-sm font-medium' }, 'Monthly Stats'),
h(HLTag, { size: 'xs', variant: 'success', round: true }, { default: () => '↑ 23%' })
]),
h('div', { class: 'flex gap-4 mt-1' }, [
h('div', { class: 'flex flex-col items-center' }, [
h('span', { class: 'text-xs font-medium' }, '1.2k'),
h('span', { class: 'text-xs text-gray-500' }, 'Views')
]),
h('div', { class: 'flex flex-col items-center' }, [
h('span', { class: 'text-xs font-medium' }, '8.4k'),
h('span', { class: 'text-xs text-gray-500' }, 'Clicks')
]),
h('div', { class: 'flex flex-col items-center' }, [
h('span', { class: 'text-xs font-medium' }, '98%'),
h('span', { class: 'text-xs text-gray-500' }, 'Rating')
])
])
])
},
{
key: 'team-member',
label: 'Team Member',
type: 'render',
render: () => h('div', { class: 'p-2 flex items-center justify-between' }, [
h('div', { class: 'flex items-center gap-3' }, [
h('img', {
src: 'https://ui-avatars.com/api/?name=Sarah+Wilson',
class: 'w-8 h-8 rounded-full',
alt: 'Sarah Wilson'
}),
h('div', { class: 'flex flex-col' }, [
h('div', { class: 'text-sm font-medium' }, 'Sarah Wilson'),
h('div', { class: 'text-xs text-gray-500 flex items-center gap-1' }, [
h('div', { class: 'w-1.5 h-1.5 rounded-full bg-success-500' }),
'Online'
])
])
]),
h('div', { class: 'flex gap-2' }, [
h(HLTag, { size: 'xs', variant: 'warning' }, { default: () => 'Lead' })
])
])
}
]"
]Multiple Selection
The dropdown component supports multiple selection mode, which allows users to select multiple options. You can also control whether the dropdown should close after selection by setting the closeOnSelect prop to false. The showSelectedMark prop can be used to show a checkmark next to the selected option.
<template>
<HLDropdown
id="multiple-dropdown"
trigger="click"
placement="bottom"
:options="options"
multiple
:closeOnSelect="false"
show-selected-mark
:width="280"
>
<HLButton size="sm">Multiple Selection</HLButton>
</HLDropdown>
</template>
<script setup>
const options = [
{
key: 'fruits',
label: 'Fruits',
children: [
{ key: 'apple', label: 'Apple' },
{ key: 'banana', label: 'Banana' },
{ key: 'orange', label: 'Orange' },
],
},
{
key: 'vegetables',
label: 'Vegetables',
children: [
{ key: 'carrot', label: 'Carrot' },
{ key: 'broccoli', label: 'Broccoli' },
{ key: 'potato', label: 'Potato' },
],
},
]
</script>Disabled Options
You can disable individual options by setting the disabled key to true on the dropdown option. Disabled options cannot be selected and do not emit the select event when clicked and display a not-allowed cursor on hover.
<template>
<HLDropdown id="disabled-dropdown" trigger="click" placement="bottom" :options="disabledOptions" :width="280">
<HLButton size="sm">Disabled Options</HLButton>
</HLDropdown>
</template>const disabledOptions = [
{
key: 'option1',
label: 'Enabled Option',
description: 'This option is selectable',
},
{
key: 'option2',
label: 'Disabled Option',
description: 'This option cannot be selected',
disabled: true,
},
{
key: 'group',
label: 'Mixed Group',
children: [
{ key: 'enabled', label: 'Enabled Child' },
{ key: 'disabled-child', label: 'Disabled Child', disabled: true },
],
},
]Disabled Dropdown
You can also disable the entire dropdown by setting the disabled prop on the dropdown component.
WARNING
A disabled dropdown cannot be opened, but the trigger itself remains active. To disable the trigger, it must be explicitly set as disabled.
<template>
<HLDropdown id="disabled-entire-dropdown" trigger="click" placement="bottom" :options="simpleOptions" disabled :width="200">
<HLButton size="sm">Disabled Dropdown</HLButton>
</HLDropdown>
</template>Props
Dropdown Props
| Prop | Type | Default | Description |
|---|---|---|---|
| id * | string | undefined | undefined | Unique identifier for the dropdown. Required for accessibility and testing. |
| options | DropdownOption[] | [] | Array of options to display in the dropdown menu. See Option Properties for details. |
| trigger | 'click' | 'hover' | 'focus' | 'click' | Event that triggers the dropdown menu. |
| placement | 'top-start' | 'top' | 'top-end' | 'right-start' | 'right' | 'right-end' | 'bottom-start' | 'bottom' | 'bottom-end' | 'left-start' | 'left' | 'left-end' | 'bottom' | Position of the dropdown menu relative to the trigger element. |
| width | number | undefined | 182 | Width of the dropdown menu in pixels. |
| show | boolean | undefined | undefined | Controlled visibility state. Use with v-model:show for two-way binding. |
| showArrow | boolean | true | Shows a pointing arrow from the menu to the trigger. |
| showSelectedMark | boolean | false | Shows a checkmark next to the selected option. |
| treeMode | boolean | false | Enables hierarchical navigation for nested options. |
| showSearch | boolean | true | Shows a search input at the top of the dropdown. |
| multiple | boolean | false | Enables multiple selection mode. |
| closeOnSelect | boolean | true | Controls whether the dropdown should close after an option is selected. Selected Mark is not shown if this is set to false. |
| resetTreeOnChange | boolean | false | Controls whether the dropdown tree should reset the tree state when the dropdown is closed. |
| disabled | boolean | false | Disables the entire dropdown, preventing it from being opened. |
| maxHeight | string | undefined | undefined | Maximum height of the dropdown menu. Only applicable when tree-mode is enabled. |
| clearableInSearch | boolean | false | Whether the search input is clearable. |
DropdownOption Properties
| Property | Type | Description | Example |
|---|---|---|---|
| key | string | Unique identifier for the option. | 'edit' |
| label | string | Display text for the option. | 'Edit Post' |
| type | 'default' | 'header' | 'divider' | 'avatar' | 'icon' | 'render' | 'search' | Type of menu item to render. | 'header' |
| description | string | Secondary text shown below the label. | 'Modify post content' |
| descriptionIcon | () => VNode | Icon rendered next to description. | () => h(InfoIcon) |
| icon | () => VNode | Icon for the option. | () => h(EditIcon) |
| iconPlacement | 'left' | 'right' | Position of the icon. | 'left' |
| children | DropdownOption[] | Nested options for tree navigation. | [{ key: 'sub1', label: 'Sub Option' }] |
| src | string | Image URL for avatar type options. | '/path/to/image.png' |
| infoText | string | Additional text shown to the right. | '+1' |
| titleRightSlot | () => VNode | Custom content for the right side. | () => h(HLTag, { ... }) |
| render | () => VNode | Custom render function for the entire option. | () => h('div', { ... }) |
| disabled | boolean | Disables the option, preventing selection. | true |
| searchPlaceholder | string | Placeholder for the search input. | 'Search' |
Emits
Dropdown Emits
| Event | Arguments | Description |
|---|---|---|
@select | (key: string | number, option: DropdownOption) | Fired when an option is selected. |
@update:show | (show: boolean) | Fired when dropdown visibility changes. |
@search | (value: string) | Fired when search input changes. |
@clickoutside | (e: MouseEvent | KeyboardEvent | PointerEvent) | Fired when user clicks outside of the dropdown. |
@scroll | (event: Event) | Fired when the dropdown is scrolled. |
Slots
| Name | Parameters | Description |
|---|---|---|
| default | () | The default content slot |