Overview
The InputMenu component combines a text input with a dropdown menu, providing searchable autocomplete functionality, custom filtering, multiple selection, and the ability to create new items.
Basic Usage
<script setup lang="ts">
import { ref } from 'vue'
const selected = ref(null)
const items = [
'Apple',
'Banana',
'Cherry',
'Date',
'Elderberry'
]
</script>
<template>
<UInputMenu v-model="selected" :items="items" placeholder="Select a fruit" />
</template>
With Objects
<script setup lang="ts">
import { ref } from 'vue'
const selected = ref(null)
const items = [
{ id: 1, label: 'Wade Cooper', description: 'Software Engineer' },
{ id: 2, label: 'Arlene Mccoy', description: 'Product Manager' },
{ id: 3, label: 'Devon Webb', description: 'Designer' }
]
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
value-key="id"
placeholder="Select a person"
/>
</template>
With Icons and Avatars
<script setup lang="ts">
const items = [
{
label: 'Profile',
icon: 'i-heroicons-user',
value: 'profile'
},
{
label: 'Settings',
icon: 'i-heroicons-cog',
value: 'settings'
},
{
label: 'Team',
avatar: { src: 'https://i.pravatar.cc/150?img=1' },
value: 'team'
}
]
</script>
<template>
<UInputMenu v-model="selected" :items="items" />
</template>
Multiple Selection
<script setup lang="ts">
import { ref } from 'vue'
const selected = ref([])
const items = ['React', 'Vue', 'Angular', 'Svelte', 'Solid']
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
multiple
placeholder="Select frameworks"
/>
</template>
Create Custom Items
<script setup lang="ts">
import { ref } from 'vue'
const selected = ref(null)
const items = ref(['Apple', 'Banana', 'Cherry'])
function onCreate(item: string) {
items.value.push(item)
selected.value = item
}
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
create-item
@create="onCreate"
placeholder="Type to create..."
/>
</template>
Grouped Items
<script setup lang="ts">
const items = [
[
{ type: 'label', label: 'Fruits' },
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' }
],
[
{ type: 'label', label: 'Vegetables' },
{ label: 'Carrot', value: 'carrot' },
{ label: 'Potato', value: 'potato' }
]
]
</script>
<template>
<UInputMenu v-model="selected" :items="items" />
</template>
Custom Filtering
<script setup lang="ts">
import { ref } from 'vue'
const selected = ref(null)
const searchTerm = ref('')
const items = ref([])
// Fetch items from API based on search
watchDebounced(searchTerm, async (value) => {
if (!value) return
const { data } = await useFetch('/api/search', {
query: { q: value }
})
items.value = data.value
}, { debounce: 300 })
</script>
<template>
<UInputMenu
v-model="selected"
v-model:search-term="searchTerm"
:items="items"
ignore-filter
placeholder="Search..."
/>
</template>
Virtualization
Efficiently render large lists:
<script setup lang="ts">
const items = Array.from({ length: 10000 }, (_, i) => ({
label: `Item ${i + 1}`,
value: i
}))
</script>
<template>
<UInputMenu
v-model="selected"
:items="items"
virtualize
placeholder="Select from 10k items"
/>
</template>
<template>
<UInputMenu
v-model="selected"
:items="items"
clear
placeholder="Select an item"
@clear="console.log('Cleared')"
/>
</template>
Custom Slots
<template>
<UInputMenu v-model="selected" :items="items">
<template #item="{ item }">
<div class="flex items-center justify-between w-full">
<span>{{ item.label }}</span>
<UBadge>{{ item.count }}</UBadge>
</div>
</template>
<template #empty="{ searchTerm }">
<p>No results for "{{ searchTerm }}"</p>
</template>
</UInputMenu>
</template>
Props
The controlled value. Can be bound with v-model.
The default value when initially rendered.
Array of items or nested arrays for grouped items.
Field to use as the value when items are objects.
Field to use as the label when items are objects.
descriptionKey
string
default:"description"
Field to use as the description when items are objects.
Placeholder text when the input is empty.
Allow multiple items to be selected.
createItem
boolean | 'always' | object
Allow creating custom items. Can be configured with position and when options.
Fields to filter items by. Defaults to [labelKey].
Disable default filtering for custom filtering.
Enable virtualization for large lists.
The current search term. Can be bound with v-model:search-term.
Show a clear button to reset the value.
Icon for the clear button.
Icon shown for selected items.
Icon for delete button in tags (multiple mode).
Icon displayed at the end.
portal
boolean | string | HTMLElement
default:"true"
Render the menu in a portal.
Content props (side, sideOffset, etc.).
Display an arrow alongside the menu.
Events
Emitted when the selected value changes.
Emitted when the search term changes.
Emitted when a new item is created.
Emitted when the clear button is clicked.
Emitted when the value is committed.
@blur
(event: FocusEvent) => void
Emitted when the input loses focus.
@focus
(event: FocusEvent) => void
Emitted when the input gains focus.
Slots
leading
{ modelValue: any, open: boolean, ui: object }
Custom leading content.
trailing
{ modelValue: any, open: boolean, ui: object }
Custom trailing content.
item
{ item: any, index: number, ui: object }
Custom item rendering.
item-leading
{ item: any, index: number, ui: object }
Custom item leading content.
item-trailing
{ item: any, index: number, ui: object }
Custom item trailing content.
Custom create item label.