8.3 KiB
github, description, headlessui
| github | description | headlessui | ||||
|---|---|---|---|---|---|---|
| true | Add a customizable command palette to your app. |
|
Usage
Use a v-model to display a searchable and selectable list of commands.
::component-example
padding: false
#default :command-palette-example-basic{class="h-[257px]"}
#code
<script setup>
const people = [
{ id: 1, label: 'Wade Cooper' },
{ id: 2, label: 'Arlene Mccoy' },
{ id: 3, label: 'Devon Webb' },
{ id: 4, label: 'Tom Cook' },
{ id: 5, label: 'Tanya Fox' },
{ id: 6, label: 'Hellen Schmidt' },
{ id: 7, label: 'Caroline Schultz' },
{ id: 8, label: 'Mason Heaney' },
{ id: 9, label: 'Claudie Smitham' },
{ id: 10, label: 'Emil Schaefer' }
]
const selected = ref([people[3]])
</script>
<template>
<UCommandPalette
v-model="selected"
multiple
nullable
:groups="[{ key: 'people', commands: people }]"
:fuse="{ resultLimit: 6, fuseOptions: { threshold: 0.1 } }"
/>
</template>
::
You can put a CommandPalette anywhere you want but it's most commonly used inside of a modal.
::component-example #default :command-palette-example-modal
#code
<script setup>
const isOpen = ref(false)
const people = [
{ id: 1, label: 'Wade Cooper' },
{ id: 2, label: 'Arlene Mccoy' },
{ id: 3, label: 'Devon Webb' },
{ id: 4, label: 'Tom Cook' },
{ id: 5, label: 'Tanya Fox' },
{ id: 6, label: 'Hellen Schmidt' },
{ id: 7, label: 'Caroline Schultz' },
{ id: 8, label: 'Mason Heaney' },
{ id: 9, label: 'Claudie Smitham' },
{ id: 10, label: 'Emil Schaefer' }
]
const selected = ref([])
</script>
<template>
<div>
<UButton label="Open" @click="isOpen = true" />
<UModal v-model="isOpen">
<UCommandPalette
v-model="selected"
multiple
nullable
:groups="[{ key: 'people', commands: people }]"
/>
</UModal>
</div>
</template>
::
You can pass multiple groups of commands to the component. Each group will be separated by a divider and will display a label.
Without a v-model, you can also listen on @update:model-value to navigate to a link or do something else when a command is clicked.
::component-example
padding: false
#default :command-palette-example-groups{class="h-[274px]"}
#code
<script setup>
const router = useRouter()
const commandPaletteRef = ref()
const users = [
{ 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' } }
]
const actions = [
{ id: 'new-file', label: 'Add new file', icon: 'i-heroicons-document-plus', click: () => alert('New file'), shortcuts: ['⌘', 'N'] },
{ id: 'new-folder', label: 'Add new folder', icon: 'i-heroicons-folder-plus', click: () => alert('New folder'), shortcuts: ['⌘', 'F'] },
{ id: 'hashtag', label: 'Add hashtag', icon: 'i-heroicons-hashtag', click: () => alert('Add hashtag'), shortcuts: ['⌘', 'H'] },
{ id: 'label', label: 'Add label', icon: 'i-heroicons-tag', click: () => alert('Add label'), shortcuts: ['⌘', 'L'] }
]
const groups = computed(() => commandPaletteRef.value?.query
? [{
key: 'users',
commands: users
}]
: [{
key: 'recent',
label: 'Recent searches',
commands: users.slice(0, 1)
}, {
key: 'actions',
commands: actions
}])
function onSelect (option) {
if (option.click) {
option.click()
} else if (option.to) {
router.push(option.to)
} else if (option.href) {
window.open(option.href, '_blank')
}
}
</script>
<template>
<UCommandPalette ref="commandPaletteRef" :groups="groups" @update:model-value="onSelect" />
</template>
::
Icon
Use any icon from Iconify by setting the icon prop by using this pattern: i-{collection_name}-{icon_name}.
Use the selectedIcon prop to set a different icon or change it globally in ui.commandPalette.default.selectedIcon. Defaults to i-heroicons-check-20-solid.
::component-card
padding: false baseProps: empty: null props: icon: 'i-heroicons-command-line' excludedProps:
- icon
::
Placeholder
Use the placeholder prop to change the input placeholder
::component-card
padding: false baseProps: empty: null props: placeholder: 'Type a command...' excludedProps:
- icon
::
Close
Use the close prop to display a close button on the right side of the input.
You can pass all the props of the Button component to customize it through the close prop or globally through ui.commandPalette.default.close.
::component-card
padding: false baseProps: empty: null props: close: icon: 'i-heroicons-x-mark-20-solid' color: 'gray' variant: 'link' padded: false excludedProps:
- close
::
Empty
Use the empty prop to display a message when there are no results.
You can pass an object through the empty prop or globally through ui.commandPalette.default.empty. Here is the default:
::component-card
padding: false baseProps: placeholder: 'Type something to see the empty label change' props: empty: icon: 'i-heroicons-magnifying-glass-20-solid' label: "We couldn't find any items." queryLabel: "We couldn't find any items with that term. Please try again." excludedProps:
- empty
::
Full-text search
The CommandPalette component takes care of the full-text search for you with Fuse.js. You can pass all the options of Fuse.js through the fuse prop.
When searching for a command, the component will look for a label property on the command by default. You can customize this behaviour by overriding the commandAttribute prop. This will also affect the display of the command.
You can also highlight the matches in the command by setting the fuse.fuseOptions.includeMatches to true. The CommandPalette component automatically takes care of the highlighting for you.
<template>
<UCommandPalette
command-attribute="title"
:fuse="{
fuseOptions: {
ignoreLocation: true,
includeMatches: true,
threshold: 0,
keys: ['title', 'description', 'children.children.value', 'children.children.children.value']
},
resultLimit: 10
}"
/>
</template>
::alert{icon="i-heroicons-light-bulb"} Try it yourself in this documentation's search by pressing :badge-shortcut{value="meta"} :badge-shortcut{value="K" class="ml-1"}. ::
Async search
You can also pass an async function to the search property of a group to perform an async search. The function will receive the query as its first argument and should return an array of commands.
::component-example
padding: false
#default :command-palette-example-async{class="h-[274px]"} #code
<script setup>
const groups = computed(() => {
return [{
key: 'users',
label: q => q && `Users matching “${q}”...`,
search: async (q) => {
if (!q) {
return []
}
const users = await $fetch(`https://jsonplaceholder.typicode.com/users`, { params: { q } })
return users.map(user => ({ id: user.id, label: user.name, suffix: user.email }))
}
}].filter(Boolean)
})
</script>
<template>
<UCommandPalette :groups="groups" />
</template>
::
Themes
Our theming system provides a lot of flexibility to customize the component. Here is some examples of what you can do.
Algolia
::component-example
padding: false
#default :command-palette-theme-algolia{class="max-h-[480px] rounded-md"} ::
::alert{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeAlgolia.vue#L23"} Take a look at the component! ::
Raycast
::component-example
padding: false
#default :command-palette-theme-raycast{class="max-h-[480px] rounded-md"} ::
::alert{icon="i-simple-icons-github" to="https://github.com/nuxtlabs/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeRaycast.vue#L30"} Take a look at the component! ::
Props
:component-props
Preset
:component-preset