Command
A list of everything the app can do, opened with one key and searched by typing: the fastest way around an interface for someone who keeps their hands on the keyboard.
<script setup lang="ts">
import { Palette, Rocket, RotateCcw, Settings, Terminal } from '@lucide/vue'
import type { CommandItem } from 'oyna-ui'
import { ref } from 'vue'
const open = ref(false)
const commands: CommandItem[] = [
{ value: 'deploy', label: 'Deploy to production', group: 'Deploys', icon: Rocket, hint: 'v1.4.1' },
{ value: 'rollback', label: 'Roll back', group: 'Deploys', icon: RotateCcw, keywords: 'revert undo' },
{ value: 'logs', label: 'Open the logs', group: 'Deploys', icon: Terminal },
{ value: 'theme', label: 'Theme editor', group: 'Go to', icon: Palette },
{ value: 'settings', label: 'Settings', group: 'Go to', icon: Settings, keywords: 'preferences account' },
{ value: 'billing', label: 'Billing', group: 'Go to', disabled: true, hint: 'owners only' },
]
function run(item: CommandItem) {
// item.value tells which one
}
</script>
<template>
<OButton hotkey="KeyK" @click="open = true">Commands</OButton>
<OCommand v-model:open="open" :items="commands" @select="run" />
</template>The field has the focus as soon as the palette opens. The arrow keys move through the list, Enter runs the lit item, Esc closes. Choosing an item closes the palette and emits select with that item; what it does is up to you.
How it searches
Every typed word must occur in the item's label, group or keywords, in any order: dep prod finds "Deploy to production", and undo finds "Roll back" through its keywords. Put the words people might try, but which are not on the label, into keywords.
Opening it
The palette has no key of its own. Open it from a button that owns a hotkey, as above, or with useHotkey. Hotkeys are single physical keys, so the palette here opens on K; a combination such as Ctrl+K is yours to listen for.
Your own search
By default the palette filters items itself. With :filter="false" it shows them as given, and tells you what is typed through v-model:query: the search is then yours — a request to a server, or one with its own idea of what comes first. An item's description is a second, dimmer line under its label, for the words around a match.
<script setup lang="ts">
import type { CommandItem } from 'oyna-ui'
import { ref, watch } from 'vue'
const open = ref(false)
const query = ref('')
const results = ref<CommandItem[]>([])
watch(query, async (text) => {
const found = await search(text)
results.value = found.map((page) => ({
value: page.url,
label: page.title,
hint: page.section,
description: page.excerpt,
}))
})
</script>
<template>
<OCommand v-model:open="open" v-model:query="query" :items="results" :filter="false" title="Search" @select="go">
<template #footer>
<span><OKbd>↑</OKbd> <OKbd>↓</OKbd> to choose · <OKbd>Enter</OKbd> to open</span>
</template>
</OCommand>
</template>The footer slot stands under the list. The search of this site (press /) is built exactly this way.
Without groups
Items without a group form one plain list. title, placeholder and empty-text set the words.
<OCommand
v-model:open="open"
:items="pages"
title="Go to"
placeholder="A page"
empty-text="No such page"
@select="go"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | CommandItem[] | required | |
v-model:open | boolean | false | |
title | string | 'Commands' | The dialog's title |
placeholder | string | 'Type a command' | |
emptyText | string | 'Nothing found' | Shown when nothing matches the text |
filter | boolean | true | false shows the items as given: you narrow them yourself |
v-model:query | string | '' | What is typed in the field |
CommandItem
| Field | Type | Description |
|---|---|---|
value | string | What tells the items apart |
label | string | The text of the row |
group | string | Items with the same group stand together under its name |
hint | string | A dim note at the end of the row |
description | string | A second, dimmer line under the label |
keywords | string | Extra words the item is found by |
icon | Component | An icon component, e.g. from Lucide |
disabled | boolean |
Slots
| Slot | Description |
|---|---|
footer | Under the list: a hint about the keys, a link |
Events
| Event | Payload | Description |
|---|---|---|
select | CommandItem | An item was chosen |