Skip to content

Combobox ​

A neo-brutalist style searchable select component. Toggle between single-select and multi-select modes via the multiple prop.

Demo ​

Preview

加载状态

点击按钮触发 loading,列表底部显示 Spinner。

创建选项(单选)

输入无匹配项时显示「创建」选项,创建后关闭下拉。

创建选项(多选)

创建后不关闭下拉,可继续创建多项。

Installation ​

pnpm dlx brutx-vue@latest add combobox

Usage ​

Single-select Mode ​

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

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

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

ts
interface ComboboxOption {
    value: string
    label: string
    disabled?: boolean
}

API Reference ​

Combobox — Props
NameTypeDefaultDescription
options
Required
ComboboxOption[]
—
The available options. Each item has a string value, a display label, and an optional disabled flag.
Details

Declared type

ComboboxOption[]

Referenced types

ComboboxOption
Type definition — ComboboxOption
export interface ComboboxOption {
    value: string
    label: string
    disabled?: boolean
}

Default value details

Not declared
—

Source

Combobox.vue:24

packages/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.
Details

Declared type

string | string[] | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:25

packages/ui/src/components/combobox/Combobox.vue

multiple
boolean | undefined
false
Enables multiple selection so users can choose more than one option.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
false

Source

Combobox.vue:26

packages/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.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
undefined

Source

Combobox.vue:27

packages/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.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:28

packages/ui/src/components/combobox/Combobox.vue

searchPlaceholder
string | undefined
undefined
Placeholder for the search field inside the dropdown; localized text is used when omitted.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:29

packages/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.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:30

packages/ui/src/components/combobox/Combobox.vue

disabled
boolean | undefined
false
Disables the trigger and option interactions.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
false

Source

Combobox.vue:31

packages/ui/src/components/combobox/Combobox.vue

loading
boolean | undefined
false
Shows a loading state while options are being prepared or refreshed asynchronously.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
false

Source

Combobox.vue:32

packages/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.
Details

Declared type

boolean | undefined

Literal values

  • false
  • true

Default value details

Resolved value
false

Source

Combobox.vue:33

packages/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.
Details

Declared type

number | undefined

Default value details

Resolved value
3

Source

Combobox.vue:34

packages/ui/src/components/combobox/Combobox.vue

ariaLabel
string | undefined
undefined
Sets the accessible name of the combobox trigger.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:35

packages/ui/src/components/combobox/Combobox.vue

class
string | undefined
undefined
Custom CSS classes added to the combobox root container.
Details

Declared type

string | undefined

Default value details

Resolved value
undefined

Source

Combobox.vue:36

packages/ui/src/components/combobox/Combobox.vue

iconSize
IconSize | undefined
"md"
Sets the size of the dropdown indicator icon.
Details

Declared type

IconSize | undefined

Literal values

  • "2xl"
  • "lg"
  • "md"
  • "sm"
  • "xl"
  • "xs"

Referenced types

IconSize
Type definition — IconSize
export type IconSize = NonNullable<VariantProps<typeof iconSizeVariants>['size']>

Default value details

Resolved value
"md"

Source

Combobox.vue:37

packages/ui/src/components/combobox/Combobox.vue

Combobox — Events
NameSignature or typeDescription
@update:modelValue
[value: string | string[] | undefined]
Emits the new selection; multiple mode emits an array, while selecting the current single option again emits undefined.
Details

Declared type

[value: string | string[] | undefined]

Source

Combobox.vue

packages/ui/src/components/combobox/Combobox.vue

@update:open
[value: boolean]
Emits the requested boolean state when the dropdown opens or closes.
Details

Declared type

[value: boolean]

Literal values

  • false
  • true

Source

Combobox.vue

packages/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.
Details

Declared type

[value: string]

Source

Combobox.vue

packages/ui/src/components/combobox/Combobox.vue

Combobox — Exposes
NameSignature or typeDescription
searchQuery
string
The current search text; it is cleared when the panel closes or a single selection completes.
Details

Declared type

string

Source

Combobox.vue:194

packages/ui/src/components/combobox/Combobox.vue

selectedValue
string | string[] | undefined
A read-only computed value of the current modelValue.
Details

Declared type

string | string[] | undefined

Source

Combobox.vue:195

packages/ui/src/components/combobox/Combobox.vue

focus
() => void | undefined
Moves keyboard focus to the combobox trigger.
Details

Declared type

() => void | undefined

Source

Combobox.vue:196

packages/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.
Details

Declared type

WritableComputedRef<boolean, boolean>

Literal values

  • false
  • true

Source

Combobox.vue

packages/ui/src/components/combobox/Combobox.vue

Accessibility ​

  • Keyboard: Supports Arrow Up / Arrow Down to move focus, Enter to select the current item, Escape to close the dropdown
  • ARIA Attributes: Provides accessibility label via the ariaLabel prop

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.

Brute force builds.