Combobox
A neo-brutalist style searchable select component. Toggle between single-select and multi-select modes via the multiple prop.
Demo
加载状态
点击按钮触发 loading,列表底部显示 Spinner。
创建选项(单选)
输入无匹配项时显示「创建」选项,创建后关闭下拉。
创建选项(多选)
创建后不关闭下拉,可继续创建多项。
Installation
pnpm dlx brutx-vue@latest add comboboxUsage
Single-select Mode
<script setup>
import { ref } from 'vue'
import { Combobox } from 'brutx-ui-vue'
const selected = ref(undefined)
const options = [
{ value: 'vue', label: 'Vue' },
{ value: 'react', label: 'React' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
]
</script>
<template>
<Combobox
v-model="selected"
:options="options"
placeholder="Select a framework..."
search-placeholder="Search frameworks..."
/>
</template>Multi-select Mode
<script setup>
import { ref } from 'vue'
import { Combobox } from 'brutx-ui-vue'
const selected = ref([])
const options = [
{ value: 'vue', label: 'Vue' },
{ value: 'react', label: 'React' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' },
]
</script>
<template>
<Combobox
v-model="selected"
:options="options"
multiple
placeholder="Select frameworks..."
:max-display="3"
/>
</template>Loading State
When loading is set to true, a Spinner is displayed at the bottom of the dropdown list. This is useful for asynchronous option loading scenarios.
<script setup>
import { ref } from 'vue'
import { Combobox } from 'brutx-ui-vue'
const loading = ref(false)
const options = ref([])
async function handleOpen() {
loading.value = true
options.value = await fetchOptions()
loading.value = false
}
</script>
<template>
<Combobox v-model="selected" :options="options" :loading="loading" />
</template>Creating Options
When creative is set to true, if no search matches are found and the input is non-empty, a "Create '{query}'" option appears at the top of the list (text from locale combobox.create). Clicking it triggers the create event with the search text trimmed of leading/trailing whitespace as the argument (both the label and the emitted payload use the trimmed query, avoiding dirty values with stray spaces).
Combobox(single-select): Closes the dropdown after creation.Combobox(multiple): Does not close the dropdown after creation, allowing continued selection or creation of multiple items.
<script setup>
import { ref } from 'vue'
import { Combobox } from 'brutx-ui-vue'
const selected = ref(undefined)
const options = ref([
{ value: 'vue', label: 'Vue' },
{ value: 'react', label: 'React' },
])
function handleCreate(value) {
options.value.push({ value: value.toLowerCase(), label: value })
selected.value = value.toLowerCase()
}
</script>
<template>
<Combobox
v-model="selected"
:options="options"
creative
@create="handleCreate"
/>
</template>Data Types
interface ComboboxOption {
value: string
label: string
disabled?: boolean
}API Reference
| Name | Type | Default | Description |
|---|---|---|---|
optionsRequired | ComboboxOption[] | — | The available options. Each item has a string value, a display label, and an optional disabled flag. |
DetailsDeclared typeComboboxOption[] Referenced types ComboboxOption Type definition — ComboboxOptionexport interface ComboboxOption {
value: string
label: string
disabled?: boolean
}Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
modelValue | string | string[] | undefined | undefined | The selected string or array of strings, bound with v-model; multiple mode uses an array. |
DetailsDeclared typestring | string[] | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
multiple | boolean | undefined | false | Enables multiple selection so users can choose more than one option. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
open | boolean | undefined | undefined | The dropdown open state. When supplied, the state is controlled and the parent must write back update:open changes. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
placeholder | string | undefined | undefined | Placeholder shown with no selection; when omitted, localized text is chosen for single or multiple mode. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
searchPlaceholder | string | undefined | undefined | Placeholder for the search field inside the dropdown; localized text is used when omitted. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
emptyText | string | undefined | undefined | Text shown when the search has no matching options; localized text is used when omitted. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
disabled | boolean | undefined | false | Disables the trigger and option interactions. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
loading | boolean | undefined | false | Shows a loading state while options are being prepared or refreshed asynchronously. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
creative | boolean | undefined | false | Shows a create option when a non-empty query has no matches; the component emits create without changing modelValue. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
maxDisplay | number | undefined | 3 | The maximum selected tags shown in the trigger in multiple mode; additional selections are summarized by count. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
ariaLabel | string | undefined | undefined | Sets the accessible name of the combobox trigger. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
class | string | undefined | undefined | Custom CSS classes added to the combobox root container. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
iconSize | IconSize | undefined | "md" | Sets the size of the dropdown indicator icon. |
DetailsDeclared typeIconSize | undefined Literal values
Referenced types IconSize Type definition — IconSizeexport type IconSize = NonNullable<VariantProps<typeof iconSizeVariants>['size']> Default value details
Sourcepackages/ui/src/components/combobox/Combobox.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@update:modelValue | [value: string | string[] | undefined] | Emits the new selection; multiple mode emits an array, while selecting the current single option again emits undefined. |
DetailsDeclared type[value: string | string[] | undefined] Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
@update:open | [value: boolean] | Emits the requested boolean state when the dropdown opens or closes. |
DetailsDeclared type[value: boolean] Literal values
Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
@create | [value: string] | Emits the trimmed search text when the user chooses the create action; the caller adds the option and value. |
DetailsDeclared type[value: string] Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
| Name | Signature or type | Description |
|---|---|---|
searchQuery | string | The current search text; it is cleared when the panel closes or a single selection completes. |
DetailsDeclared typestring Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
selectedValue | string | string[] | undefined | A read-only computed value of the current modelValue. |
DetailsDeclared typestring | string[] | undefined Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
focus | () => void | undefined | Moves keyboard focus to the combobox trigger. |
DetailsDeclared type() => void | undefined Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
open | WritableComputedRef<boolean, boolean> | The readable and writable dropdown state. Setting true opens the panel; controlled mode still requires the parent to write back changes. |
DetailsDeclared typeWritableComputedRef<boolean, boolean> Literal values
Sourcepackages/ui/src/components/combobox/Combobox.vue | ||
Accessibility
- Keyboard: Supports
Arrow Up/Arrow Downto move focus,Enterto select the current item,Escapeto close the dropdown - ARIA Attributes: Provides accessibility label via the
ariaLabelprop
FAQ
Q: Why does clicking an already selected option in single-select mode have no effect?
A: In Combobox single-select mode, clicking an already selected option deselects it (value becomes undefined). This is by design to support clearing the selection. If you don't need this behavior, you can listen to the update:modelValue event in the parent component and restore the previous value when it becomes undefined.
Q: How do I implement asynchronous option loading?
A: Set loading to true to show the loading state, update options after data is loaded, and set loading to false. You can combine this with the dropdown open event to trigger data loading, avoiding loading all data at once.
Q: How are newly created options persisted in creative mode?
A: The component itself does not persist created options. You need to manually add the new option to the options array in the create event handler and update modelValue accordingly. For persistent storage, you can call a backend API or write to local storage in the event handler.