Files
ui/docs/content/3.forms/4.select-menu.md
2023-07-18 17:31:04 +02:00

250 lines
6.3 KiB
Markdown

---
description: Display a select menu with advanced features.
links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxtlabs/ui/blob/dev/src/runtime/components/forms/SelectMenu.vue
- label: 'Listbox'
icon: i-simple-icons-headlessui
to: 'https://headlessui.com/vue/listbox'
---
## Usage
The SelectMenu component renders by default a [Select](/forms/select) component and is based on the `ui.select` preset. You can use most of the Select props to configure the display if you don't want to override the default slot such as [color](/forms/select#style), [variant](/forms/select#style), [size](/forms/select#size), [placeholder](/forms/select#placeholder), [icon](/forms/select#icon), [disabled](/forms/select#disabled), etc.
Like the Select component, you can use the `options` prop to pass an array of strings or objects.
::component-example
#default
:select-menu-example-basic{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<USelectMenu v-model="selected" :options="people" />
</template>
```
::
### Multiple
You can use the `multiple` prop to select multiple values.
::component-example
#default
:select-menu-example-multiple{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = [...]
const selected = ref([])
</script>
<template>
<USelectMenu v-model="selected" :options="people" multiple placeholder="Select people" />
</template>
```
::
### Objects
You can pass an array of objects to `options` and either compare on the whole object or use the `by` prop to compare on a specific key. You can configure which field will be used to display the label through the `option-attribute` prop that defaults to `label`.
::component-example
#default
:select-menu-example-objects{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = [{
id: 'benjamincanac',
label: 'benjamincanac',
href: 'https://github.com/benjamincanac',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' }
},
{
id: 'Atinux',
label: 'Atinux',
href: 'https://github.com/Atinux',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/904724?v=4' }
},
{
id: 'smarroufin',
label: 'smarroufin',
href: 'https://github.com/smarroufin',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/7547335?v=4' }
},
{
id: 'nobody',
label: 'Nobody',
icon: 'i-heroicons-user-circle'
}]
const selected = ref(people[0])
</script>
<template>
<USelectMenu v-model="selected" :options="people">
<template #label>
<UIcon v-if="selected.icon" :name="selected.icon" class="w-4 h-4" />
<UAvatar v-else-if="selected.avatar" v-bind="selected.avatar" size="3xs" />
{{ selected.label }}
</template>
</USelectMenu>
</template>
```
::
### Icon
Use the `selected-icon` prop to set a different icon or change it globally in `ui.selectMenu.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
::component-card
---
baseProps:
class: 'max-w-[12rem] w-full'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
selectedIcon: 'i-heroicons-hand-thumb-up-solid'
excludedProps:
- selectedIcon
---
::
::callout{icon="i-heroicons-light-bulb"}
Learn how to customize icons from the [Select](/forms/select#icon) component.
::
### Search
Use the `searchable` prop to enable search.
Use the `searchable-placeholder` prop to set a different placeholder.
This will use Headless UI [Combobox](https://headlessui.com/vue/combobox) component instead of [Listbox](https://headlessui.com/vue/listbox).
::component-card
---
baseProps:
class: 'max-w-[12rem] w-full'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
searchable: true
searchablePlaceholder: 'Search a person...'
---
::
### Async search :u-badge{label="New" class="ml-2 align-text-bottom !rounded-full"}
Pass a function to the `searchable` prop to customize the search behavior and filter options according to your needs. The function will receive the query as its first argument and should return an array.
Use the `debounce` prop to adjust the delay of the function.
::component-example
#default
:select-menu-example-async-search{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const search = async (q) => {
const users = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
return users.map(user => ({ id: user.id, label: user.name, suffix: user.email })).filter(Boolean)
}
const selected = ref([])
</script>
<template>
<USelectMenu
v-model="selected"
:searchable="search"
placeholder="Search for a user..."
multiple
by="id"
/>
</template>
```
::
## Slots
### `label`
You can override the `#label` slot and handle the display yourself.
::component-example
#default
:select-menu-example-multiple-slot{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = [...]
const selected = ref([])
</script>
<template>
<USelectMenu v-model="selected" :options="people" multiple>
<template #label>
<span v-if="selected.length" class="truncate">{{ selected.join(', ') }}</span>
<span v-else>Select people</span>
</template>
</USelectMenu>
</template>
```
::
### `default`
You can also override the `#default` slot entirely.
::component-example
#default
:select-menu-example-button{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = [...]
const selected = ref(people[3])
</script>
<template>
<USelectMenu v-slot="{ open }" v-model="selected" :options="people">
<UButton color="gray">
{{ selected }}
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform" :class="[open && 'transform rotate-90']" />
</UButton>
</USelectMenu>
</template>
```
::
## Props
:component-props
## Preset
:component-preset