MagicCommand
MagicCommand is a flexible collection of components intended to build command palette style menus, such as Spotlight, Raycast and the like.
<template>
<magic-command-provider id="magic-command-demo" class="flex flex-col gap-6">
<magic-command-trigger view-id="initial-default-view" as-child>
<m-button>Open Menu</m-button>
</magic-command-trigger>
<div class="type-surface-body-sm text-surface-subtle">
<span>or press ⌘+K / ⌃+K</span>
</div>
<magic-command-modal :options="{ focusTrap: false }">
<m-menu-box class="h-[30rem] w-[40rem]">
<magic-command-renderer />
</m-menu-box>
</magic-command-modal>
<default-view id="initial-default-view" />
</magic-command-provider>
</template>
<script lang="ts" setup>
import { MButton, MMenuBox } from '@maas/mirror/vue'
import DefaultView from './components/DefaultView.vue'
</script>Overview
Anatomy
<template>
<magic-command-provider id="your-command-id">
<!-- modal -->
<magic-command-modal>
<magic-command-renderer />
</magic-command-modal>
<!-- drawer -->
<magic-command-drawer>
<magic-command-renderer />
</magic-command-drawer>
<!-- initial view -->
<magic-command-view :initial="true" id="your-view-id">
<magic-command-trigger>Open Menu</magic-command-trigger>
<magic-command-content>
<magic-command-item>
<!-- your content -->
</magic-command-item>
<!-- nested view -->
<magic-command-item>
<magic-command-view>
<magic-command-trigger>Open View</magic-command-trigger>
<magic-command-content>
<!-- your content -->
</magic-command-content>
</magic-command-view>
</magic-command-item>
</magic-command-content>
</magic-command-view>
<!-- optional -->
<magic-command-trigger view-id="your-view-id">
Open Menu
</magic-command-trigger>
</magic-command-provider>
</template>
<script setup>
const { open, close } = useMagicCommand('your-command-id')
</script>Custom Layout
Both MagicCommandModal and MagicCommandDrawer render a default layout out of the box. Use the #layout slot to replace the entire inner structure when you need full control. For example to remove the backdrop or customise the teleport target.
<template>
<magic-command-modal>
<template #layout>
<magic-modal-teleport>
<magic-modal-content>
<magic-command-renderer />
</magic-modal-content>
</magic-modal-teleport>
</template>
</magic-command-modal>
</template>See MagicModal and MagicDrawer for details.
Installation
CLI
Add @maas/vue-equipment to your dependencies.
pnpm install @maas/vue-equipmentnpm install @maas/vue-equipmentyarn add @maas/vue-equipmentbun install @maas/vue-equipmentVue
If you are using Vue, import and add MagicCommandPlugin to your app.
import { createApp } from 'vue'
import { MagicCommandPlugin } from '@maas/vue-equipment/plugins/MagicCommand'
const app = createApp({})
app.use(MagicCommandPlugin)Nuxt
The command palette is available as a Nuxt module. In your Nuxt config file add @maas/vue-equipment/nuxt to your modules and add MagicCommand to the plugins in your configuration.
export default defineNuxtConfig({
modules: ['@maas/vue-equipment/nuxt'],
vueEquipment: {
plugins: ['MagicCommand'],
},
})Composable
In order to interact with the command palette from anywhere within your app, we provide a useMagicCommand composable. Import it directly when needed.
import { useMagicCommand } from '@maas/vue-equipment/plugins/MagicCommand'
const { selectView } = useMagicCommand('your-command-id')
function handleClick() {
selectView('your-view-id')
}TIP
If you have installed the command palette as a Nuxt module, the composable will be auto-imported and is automatically available in your Nuxt app.
Peer Dependencies
If you haven’t installed the required peer dependencies automatically, you’ll need to install the following packages manually.
Installation
pnpm install @nuxt/kit @maas/vue-primitive @vueuse/core defunpm install @nuxt/kit @maas/vue-primitive @vueuse/core defuyarn add @nuxt/kit @maas/vue-primitive @vueuse/core defubun install @nuxt/kit @maas/vue-primitive @vueuse/core defuAPI Reference
MagicCommandProvider
The MagicCommandProvider wraps the command palette and configures all child components according to the provided options.
Props
| Prop | Type | Required |
|---|---|---|
MaybeRef<string> | true | |
boolean | false | |
MagicMenuOptions | false |
Options
To customize the command palette, override the necessary options. Any custom options will be merged with the default options.
| Option | Type | Default |
|---|---|---|
boolean | false | |
string | magic-command-content | |
string[] | false | ['Cmd+k', 'Ctrl+k'] | |
string[] | false | ['Escape'] | |
string[] | false | ['ArrowDown'] | |
string[] | false | ['ArrowUp'] | |
string[] | false | ['Enter'] | |
boolean | false |
MagicCommandView
Groups command items into a single panel and tracks which item is currently selected.
Props
| Prop | Type | Required |
|---|---|---|
MaybeRef<string> | false | |
boolean | false |
Slot Props
| Prop | Type | Description |
|---|---|---|
view-active | boolean | Whether the command palette view is currently open. |
MagicCommandDrawer
Wraps the command palette in a MagicDrawerProvider and renders teleport, backdrop and content by default. Override the full inner structure using the #layout slot.
Props
| Prop | Type | Required |
|---|---|---|
MagicCommandDrawerOptions | false |
MagicCommandModal
Wraps the command palette in a MagicModalProvider and renders teleport, backdrop and content by default. Override the full inner structure using the #layout slot.
Props
| Prop | Type | Required |
|---|---|---|
MagicCommandModalOptions | false |
MagicCommandRenderer
Renders command items dynamically from registered commands.
CSS Variables
| Variable | Default |
|---|---|
--magic-command-renderer-width | 100% |
--magic-command-renderer-height | 100% |
MagicCommandItem
A single interactive command entry.
Props
| Prop | Type | Required |
|---|---|---|
string | false | |
boolean | false |
CSS Variables
| Variable | Default |
|---|---|
--magic-command-item-cursor | default |
Slot Props
| Prop | Type | Description |
|---|---|---|
item-active | boolean | Whether the item is currently selected. |
item-disabled | boolean | Whether the item is currently disabled. |
MagicCommandTrigger
Opens or closes the command palette on click.
Props
| Prop | Type | Required |
|---|---|---|
string | false | |
boolean | false | |
false | ||
false | ||
boolean | false |
| Variable | Default |
|---|---|
--magic-command-trigger-cursor | pointer |
CSS Variables
| Variable | Default |
|---|---|
--magic-command-trigger-cursor | pointer |
Slot Props
| Prop | Type | Description |
|---|---|---|
view-active | boolean | Whether the command palette is currently open. |
trigger-disabled | boolean | Whether the trigger is currently disabled. |
Errors
| Source | Error Code | Message |
|---|---|---|
MagicCommandDrawer | missing_instance_id | MagicCommandDrawer must be nested inside MagicCommandProvider |
MagicCommandTrigger | missing_instance_id | MagicCommandTrigger must be nested inside MagicCommandProvider |
MagicCommandTrigger | missing_view_id | MagicCommandTrigger must be nested inside MagicCommandView or a viewId must be provided |
MagicCommandView | missing_instance_id | MagicCommandView must be nested inside MagicCommandProvider |
MagicCommandContent | missing_instance_id | MagicCommandContent must be nested inside MagicCommandProvider |
MagicCommandContent | missing_view_id | MagicCommandContent must be nested inside MagicCommandView |
useMagicCommand | view_id_required | viewId is required to select an item |
useMagicCommand | id_required | id is required to select an item |
useMenuItem | view_id_not_found | View {viewId} not found |
useMenuKeyListener | menu_not_active | MagicMenu {state.id} is not active |
Examples
Modal
<template>
<magic-command-provider
id="magic-command-modal-demo"
:options="{ keyListener: { open: false } }"
>
<magic-command-trigger view-id="initial-modal-view" as-child>
<m-button>Open Menu</m-button>
</magic-command-trigger>
<magic-command-modal :options="{ focusTrap: false }">
<m-menu-box class="h-[30rem] w-[40rem]">
<magic-command-renderer />
</m-menu-box>
</magic-command-modal>
<default-view id="initial-modal-view" />
</magic-command-provider>
</template>
<script lang="ts" setup>
import { MButton, MMenuBox } from '@maas/mirror/vue'
import DefaultView from './components/DefaultView.vue'
</script>Drawer
<template>
<magic-command-provider
id="magic-command-drawer-demo"
:options="{ keyListener: { open: false } }"
>
<magic-command-trigger view-id="initial-drawer-view" as-child>
<m-button>Open Menu</m-button>
</magic-command-trigger>
<magic-command-drawer :options="{ focusTrap: false }">
<div
class="h-full w-full p-2 pb-[calc(var(--magic-drawer-drag-overshoot)+0.5rem)]"
>
<m-menu-box class="h-full w-full">
<magic-command-renderer />
</m-menu-box>
</div>
</magic-command-drawer>
<default-view id="initial-drawer-view" />
</magic-command-provider>
</template>
<script lang="ts" setup>
import { MButton, MMenuBox } from '@maas/mirror/vue'
import DefaultView from './components/DefaultView.vue'
</script>
<style>
[data-id='magic-command-drawer-demo'] {
--magic-drawer-width: 40rem;
--magic-drawer-height: 30rem;
}
</style>