forms

Select Menu

Display a select menu with advanced features.

Usage

The SelectMenu component renders by default a 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, variant, size, placeholder, icon, disabled, etc.

Options

Like the Select component, you can use the options prop to pass an array of strings or objects.

<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.

<script setup>
const people = [...]

const selected = ref([])
</script>

<template>
  <USelectMenu v-model="selected" :options="people" multiple placeholder="Select people" />
</template>

Slots

You can override the #label slot and handle the display yourself.

<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>

You can also override the #default slot entirely.

<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>

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.

<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 any icon from Iconify by setting the icon prop by using this pattern: i-{collection_name}-{icon_name}.

Use the trailing-icon prop to set a different icon or change it globally in ui.select.default.trailingIcon. Defaults to i-heroicons-chevron-down-20-solid.

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.

<USelectMenu icon="i-heroicons-magnifying-glass-20-solid" color="white" />

Use the searchable prop to enable search.

Use the searchable-placeholder prop to set a different placeholder.

This will use Headless UI Combobox component instead of Listbox.

<USelectMenu searchable searchable-placeholder="Search a person..." />

Props

Prop Default Description
modelValue""string | number | Record<string, any> | unknown[]
options[]string[] | { [key: string]: any; disabled?: boolean; }[]
searchAttributesnullunknown[]
popper{}{}
namenullstring
placeholdernullstring
iconnullstring
trailingIconappConfig.ui.select.default.trailingIconstring
sizeappConfig.ui.select.default.sizestring
colorappConfig.ui.select.default.colorstring
variantappConfig.ui.select.default.variantstring
byundefinedstring
selectedIconappConfig.ui.selectMenu.default.selectedIconstring
searchablePlaceholder"Search..."string
optionAttribute"label"string
requiredfalseboolean
disabledfalseboolean
paddedtrueboolean
multiplefalseboolean
searchablefalseboolean
creatablefalseboolean
uiappConfig.ui.selectMenuany
uiSelectappConfig.ui.selectany

Preset

{
  "wrapper": "relative inline-flex",
  "container": "z-20",
  "width": "w-full",
  "height": "max-h-60",
  "base": "relative focus:outline-none overflow-y-auto scroll-py-1",
  "background": "bg-white dark:bg-gray-800",
  "shadow": "shadow-lg",
  "rounded": "rounded-md",
  "padding": "p-1",
  "ring": "ring-1 ring-gray-200 dark:ring-gray-700",
  "input": "block w-[calc(100%+0.5rem)] focus:ring-transparent text-sm px-3 py-1.5 text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border-0 border-b border-gray-200 dark:border-gray-700 focus:border-inherit sticky -top-1 -mt-1 mb-1 -mx-1 z-10 placeholder-gray-400 dark:placeholder-gray-500",
  "option": {
    "base": "cursor-default select-none relative flex items-center justify-between gap-1",
    "rounded": "rounded-md",
    "padding": "px-2 py-1.5",
    "size": "text-sm",
    "color": "text-gray-900 dark:text-white",
    "container": "flex items-center gap-2 min-w-0",
    "active": "bg-gray-100 dark:bg-gray-900",
    "inactive": "",
    "selected": "pr-7",
    "disabled": "cursor-not-allowed opacity-50",
    "empty": "text-sm text-gray-400 dark:text-gray-500 px-2 py-1.5",
    "icon": {
      "base": "flex-shrink-0 h-4 w-4",
      "active": "text-gray-900 dark:text-white",
      "inactive": "text-gray-400 dark:text-gray-500"
    },
    "selectedIcon": {
      "wrapper": "absolute inset-y-0 right-0 flex items-center",
      "padding": "pr-2",
      "base": "h-4 w-4 text-gray-900 dark:text-white flex-shrink-0"
    },
    "avatar": {
      "base": "flex-shrink-0",
      "size": "3xs"
    },
    "chip": {
      "base": "flex-shrink-0 w-2 h-2 mx-1 rounded-full"
    }
  },
  "transition": {
    "leaveActiveClass": "transition ease-in duration-100",
    "leaveFromClass": "opacity-100",
    "leaveToClass": "opacity-0"
  },
  "popper": {
    "placement": "bottom-end"
  },
  "default": {
    "selectedIcon": "i-heroicons-check-20-solid"
  }
}

Made by