Skip to content
Sponsored by

MagicCommand

MagicCommand is a flexible collection of components intended to build command palette style menus, such as Spotlight, Raycast and the like.

or press ⌘+K / ⌃+K
<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

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

Installation

CLI

Add @maas/vue-equipment to your dependencies.

sh
pnpm install @maas/vue-equipment
sh
npm install @maas/vue-equipment
sh
yarn add @maas/vue-equipment
sh
bun install @maas/vue-equipment

Vue

If you are using Vue, import and add MagicCommandPlugin to your app.

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

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

js
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

sh
pnpm install @nuxt/kit @maas/vue-primitive @vueuse/core defu
sh
npm install @nuxt/kit @maas/vue-primitive @vueuse/core defu
sh
yarn add @nuxt/kit @maas/vue-primitive @vueuse/core defu
sh
bun install @nuxt/kit @maas/vue-primitive @vueuse/core defu

API Reference

MagicCommandProvider

The MagicCommandProvider wraps the command palette and configures all child components according to the provided options.

Props

PropTypeRequired
id
MaybeRef<string>true
asChild
booleanfalse
options
MagicMenuOptionsfalse

Options

To customize the command palette, override the necessary options. Any custom options will be merged with the default options.

OptionTypeDefault
debug
booleanfalse
transition.content
stringmagic-command-content
keyListener.open
string[] | false['Cmd+k', 'Ctrl+k']
keyListener.close
string[] | false['Escape']
keyListener.next
string[] | false['ArrowDown']
keyListener.prev
string[] | false['ArrowUp']
keyListener.enter
string[] | false['Enter']
loop
booleanfalse

MagicCommandView

Props

PropTypeRequired
id
MaybeRef<string>false
initial
booleanfalse

MagicCommandDrawer

Props

PropTypeRequired
Options
MagicCommandDrawerOptionsfalse

MagicCommandModal

Props

PropTypeRequired
Options
MagicCommandModalOptionsfalse

MagicCommandRenderer

CSS Variables

VariableDefault
--magic-command-renderer-width100%
--magic-command-renderer-height100%

MagicCommandItem

Props

PropTypeRequired
id
stringfalse
disabled
booleanfalse

CSS Variables

VariableDefault
--magic-command-item-cursordefault

MagicCommandTrigger

Props

PropTypeRequired
viewId
stringfalse
disabled
booleanfalse
active
booleanfalse
trigger
Interaction[]
false
Action
Action
false
asChild
booleanfalse
VariableDefault
--magic-command-trigger-cursorpointer

CSS Variables

VariableDefault
--magic-command-trigger-cursorpointer

Errors

SourceError CodeMessage
MagicCommandDrawermissing_instance_idMagicCommandDrawer must be nested inside MagicCommandProvider
MagicCommandTriggermissing_instance_idMagicCommandTrigger must be nested inside MagicCommandProvider
MagicCommandTriggermissing_view_idMagicCommandTrigger must be nested inside MagicCommandView or a viewId must be provided
MagicCommandViewmissing_instance_idMagicCommandView must be nested inside MagicCommandProvider
MagicCommandContentmissing_instance_idMagicCommandContent must be nested inside MagicCommandProvider
MagicCommandContentmissing_view_idMagicCommandContent must be nested inside MagicCommandView
useMagicCommandview_id_requiredviewId is required to select an item
useMagicCommandid_requiredid is required to select an item
useMenuItemview_id_not_foundView {viewId} not found
useMenuKeyListenermenu_not_activeMagicMenu {state.id} is not active

Examples

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