Command
A neo-brutalist style command palette component for search and navigation. Built on reka-ui's Listbox primitive with built-in search filtering.
Demo
基础用法
未找到结果。
命令对话框
程序化控制(filterSearch)
通过 ref 写入 filterSearch 可在不操作输入框的情况下触发过滤。
未找到结果。
Installation
pnpm dlx brutx-vue@latest add commandUsage
<script setup>
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut } from 'brutx-ui-vue'
</script>
<template>
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup title="Suggestions">
<CommandItem value="calendar">Calendar</CommandItem>
<CommandItem value="search">Search Emoji</CommandItem>
<CommandItem value="calculator">Calculator</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup title="Settings">
<CommandItem value="profile">
Profile
<CommandShortcut>⌘P</CommandShortcut>
</CommandItem>
<CommandItem value="billing">
Billing
<CommandShortcut>⌘B</CommandShortcut>
</CommandItem>
<CommandItem value="settings">
Settings
<CommandShortcut>⌘S</CommandShortcut>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</template>Search Filtering
Text entered in CommandInput automatically filters CommandItem elements. The matching logic is based on item text content. When all items are filtered out, CommandEmpty is automatically displayed; when all items within a group are filtered out, that group is automatically hidden.
<Command>
<CommandInput />
<CommandList>
<CommandEmpty />
<CommandGroup title="Suggestions">
<CommandItem value="calendar">Calendar</CommandItem>
<CommandItem value="search">Search Emoji</CommandItem>
</CommandGroup>
<CommandGroup title="Settings">
<CommandItem value="profile">Profile</CommandItem>
</CommandGroup>
</CommandList>
</Command>Disable Internal Filtering
When an external component handles filtering logic (e.g., Combobox), use disable-filter to disable Command's internal search filtering to avoid double-filtering conflicts:
<Command disable-filter>
<CommandInput v-model="searchQuery" />
<CommandList>
<CommandEmpty />
<CommandGroup>
<CommandItem
v-for="item in filteredItems"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>Search Widget Recipe
New code can compose Command disable-filter directly for search input, grouped results, recent searches, and loading states.
<script setup>
import { computed, ref } from 'vue'
import {
Command,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
} from 'brutx-ui-vue'
const query = ref('')
const suggestions = [
{ label: 'Button', value: 'button', group: 'Components' },
{ label: 'Theming', value: 'theming', group: 'Docs' },
]
const filteredItems = computed(() =>
suggestions.filter(item => item.label.toLowerCase().includes(query.value.toLowerCase()))
)
</script>
<template>
<Command disable-filter class="w-full max-w-lg border-3 border-brutal shadow-brutal">
<CommandInput v-model="query" placeholder="Search components or docs..." />
<CommandList>
<CommandEmpty />
<CommandGroup title="Search Results">
<CommandItem v-for="item in filteredItems" :key="item.value" :value="item.value">
{{ item.label }}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</template>Command Dialog
Use CommandDialog to create a modal command palette. Note that CommandDialog is a fully controlled component: you must bind v-model:open (or listen to update:open), otherwise user interactions (such as Escape or clicking the overlay) will not change the open/close state.
<script setup>
import { ref } from 'vue'
import { CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from 'brutx-ui-vue'
const open = ref(false)
</script>
<template>
<button @click="open = true">Open Command Palette</button>
<CommandDialog v-model:open="open">
<CommandInput placeholder="Type a command..." />
<CommandList>
<CommandEmpty />
<CommandGroup title="Actions">
<CommandItem value="new">New File</CommandItem>
<CommandItem value="open">Open File</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
</template>Sub-components
| Component | Description |
|---|---|
Command | Root container, manages filter state, built on ListboxRoot |
CommandDialog | Modal dialog wrapper, built on DialogRoot |
CommandInput | Search input field, automatically filters items on input |
CommandList | Scrollable list container, built on ListboxContent, must be used inside Command |
CommandEmpty | Displayed when there are no matching results |
CommandGroup | Grouped section with title, automatically hidden when filtered empty |
CommandItem | Selectable item, built on ListboxItem, supports @select event |
CommandSeparator | Visual separator between groups |
CommandShortcut | Keyboard shortcut hint |
Programmatic Control
Command exposes a filterSearch reactive reference via defineExpose, allowing parent components to programmatically read or set the search keyword, thereby triggering item filtering without relying on CommandInput. When a CommandInput is present, writing filterSearch externally is also reflected back into the input; if the written value differs from the input's current display, CommandInput also synchronously emits update:modelValue, keeping the parent's v-model in sync with the input display (the parent-driven v-model write-back path does not re-emit, so there is no loop).
Note: Writing to
filterSearchonly triggers filtering logic when internal filtering is enabled (i.e.,disable-filteris not set); whendisableFilteristrue, internal filtering is disabled and writes will not affect item display.
<script setup>
import { ref } from 'vue'
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from 'brutx-ui-vue'
const commandRef = ref()
</script>
<template>
<Command ref="commandRef">
<CommandInput />
<CommandList>
<CommandEmpty />
<CommandGroup title="Suggestions">
<CommandItem value="calendar">Calendar</CommandItem>
<CommandItem value="search">Search Emoji</CommandItem>
<CommandItem value="calculator">Calculator</CommandItem>
</CommandGroup>
</CommandList>
</Command>
<button @click="commandRef?.filterSearch = 'cal'">Trigger search "cal" externally</button>
<button @click="commandRef?.filterSearch = ''">Clear search</button>
</template>API Reference
Command
| Name | Type | Default | Description |
|---|---|---|---|
classNullable | ClassValue | undefined | Class values appended to the command root container. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/Command.vue | |||
disableFilter | boolean | undefined | false | Disables internal filtering of item text, for cases where the list is filtered externally. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/command/Command.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Contains child components such as the command input, list, groups, and items. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/Command.vue | ||
| Name | Signature or type | Description |
|---|---|---|
filterSearch | string | The current shared search query. Assigning a new string updates internal matching; when disableFilter is true, unmatched items are not hidden. |
DetailsDeclared typestring Sourcepackages/ui/src/components/command/Command.vue | ||
CommandDialog
| Name | Type | Default | Description |
|---|---|---|---|
open | boolean | undefined | false | The current dialog open state. The component is fully controlled, so update it through v-model:open or by handling update:open. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandDialog.vue | |||
title | string | undefined | undefinedRuntime fallback: | The accessible title for the command dialog. Blank or whitespace-only values fall back to the localized title. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/command/CommandDialog.vue | |||
description | string | undefined | undefinedRuntime fallback: | The accessible description for the command dialog. Blank or whitespace-only values fall back to the localized description. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/command/CommandDialog.vue | |||
classNullable | ClassValue | undefined | Class values appended to the dialog content; structural layout classes are merged after this value. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandDialog.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@update:open | [value: boolean] | Emits the new boolean when the dialog root requests an open-state change; the parent must still update open. |
DetailsDeclared type[value: boolean] Literal values
Sourcepackages/ui/src/components/command/CommandDialog.vue | ||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Contains dialog content such as the command input, list, groups, and items. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandDialog.vue | ||
CommandEmpty
| Name | Type | Default | Description |
|---|---|---|---|
classNullable | ClassValue | — | Class values appended to the no-results paragraph. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandEmpty.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Custom content for the empty search state; rendered only when the internal result count is zero. Localized text is used when no slot content is provided.
|
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandEmpty.vue | ||
CommandGroup
| Name | Type | Default | Description |
|---|---|---|---|
title | string | undefined | — | The group heading, rendered before the group items when a non-empty value is provided. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/command/CommandGroup.vue | |||
classNullable | ClassValue | — | Class values appended to the command group root element. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandGroup.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Contains the CommandItem children belonging to this group. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandGroup.vue | ||
CommandInput
| Name | Type | Default | Description |
|---|---|---|---|
modelValue | string | undefined | undefined | The controlled command search value. When omitted, the input initially reads the shared search query from the root Command. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/command/CommandInput.vue | |||
placeholder | string | undefined | undefinedRuntime fallback: | The input placeholder. The localized default is used only for undefined or null; an empty string is kept as an explicit value. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/command/CommandInput.vue | |||
classNullable | ClassValue | undefined | Class values appended to the native search input. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandInput.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@update:modelValue | [value: string] | Emits the new string when the user types. It also emits the synchronized value when the shared query in the root Command changes externally. |
DetailsDeclared type[value: string] Sourcepackages/ui/src/components/command/CommandInput.vue | ||
CommandItem
| Name | Type | Default | Description |
|---|---|---|---|
valueRequired | string | — | The unique command item value. It seeds the search index, which is updated to the visible text after the default slot renders. |
DetailsDeclared typestring Default value details
Sourcepackages/ui/src/components/command/CommandItem.vue | |||
disabled | boolean | undefined | — | Disables the item and passes the disabled state to the Reka UI listbox item. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandItem.vue | |||
classNullable | ClassValue | — | Class values appended to the command item root element. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandItem.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@select | [value: string] | Emitted with the item’s value string when the item is selected. |
DetailsDeclared type[value: string] Sourcepackages/ui/src/components/command/CommandItem.vue | ||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Renders the command item content. Its rendered visible text can be used for search matching. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandItem.vue | ||
CommandList
| Name | Type | Default | Description |
|---|---|---|---|
classNullable | ClassValue | — | Class values appended to the Reka UI listbox content element. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandList.vue | |||
asChild | boolean | undefined | — | Merges the listbox content props and behavior into its single child, which becomes the rendered node. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandList.vue | |||
as | AsTag | Component | undefined | — | Specifies the element or component used to render the listbox content; asChild can override it. |
DetailsDeclared typeAsTag | Component | undefined Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandList.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Contains list content such as CommandEmpty and CommandGroup. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandList.vue | ||
CommandSeparator
| Name | Type | Default | Description |
|---|---|---|---|
classNullable | ClassValue | — | Class values appended to the command separator root element. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandSeparator.vue | |||
CommandShortcut
| Name | Type | Default | Description |
|---|---|---|---|
classNullable | ClassValue | — | Class values appended to the shortcut hint element. |
DetailsDeclared typeClassValue Literal values
Default value details
Sourcepackages/ui/src/components/command/CommandShortcut.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Renders the keyboard shortcut hint associated with a command item. |
DetailsDeclared type{}Sourcepackages/ui/src/components/command/CommandShortcut.vue | ||
Accessibility
- Keyboard: Supports
↑/↓to move focus up and down,Enterto select the current item,Escapeto close the dialog (when inside CommandDialog) - ARIA Attributes: CommandDialog supports
titleanddescriptionprops for accessibility - Focus Management: Focus is trapped within the component when the dialog is open; focus is restored when closed