Command

A fast, keyboard-driven command palette with search, groups and shortcuts.

Calendar
Search emoji
Calculator
Profile⌘P
Billing⌘B
Settings⌘S

Pick a command with the arrow keys and Enter.

'use client'

import * as React from 'react'
import {
  Command,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandSeparator,
  CommandShortcut,
} from '@/components/ui/command'

interface Action {
  value: string
  label: string
  shortcut?: string
}

const groups = [
  {
    value: 'Suggestions',
    items: [
      { value: 'calendar', label: 'Calendar' },
      { value: 'emoji', label: 'Search emoji' },
      { value: 'calculator', label: 'Calculator' },
    ],
  },
  {
    value: 'Settings',
    items: [
      { value: 'profile', label: 'Profile', shortcut: '⌘P' },
      { value: 'billing', label: 'Billing', shortcut: '⌘B' },
      { value: 'settings', label: 'Settings', shortcut: '⌘S' },
    ],
  },
]

export default function CommandDemo() {
  const [last, setLast] = React.useState<string | null>(null)

  return (
    <div className="grid w-full max-w-md gap-3">
      <Command items={groups}>
        <CommandInput placeholder="Type a command or search…" />
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandList>
          {(group: (typeof groups)[number], index: number) => (
            <React.Fragment key={group.value}>
              {index > 0 && <CommandSeparator />}
              <CommandGroup items={group.items} heading={group.value}>
                {(item: Action) => (
                  <CommandItem key={item.value} value={item} onClick={() => setLast(item.label)}>
                    {item.label}
                    {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
                  </CommandItem>
                )}
              </CommandGroup>
            </React.Fragment>
          )}
        </CommandList>
      </Command>
      <p className="text-center text-sm text-muted-foreground" aria-live="polite">
        {last ? `Ran “${last}”` : 'Pick a command with the arrow keys and Enter.'}
      </p>
    </div>
  )
}

Built on Base UI

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/command.json

Needs a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.

Command imports cn() from lib/utils.ts — add it too if you don't have it yet:

import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

CommandDialog is built on Dialog. The CLI installs it for you; if you copy manually, add components/ui/dialog.tsx too.

Usage

import {
  Command,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandSeparator,
  CommandShortcut,
} from '@/components/ui/command'

const groups = [
  { value: 'Suggestions', items: [{ value: 'calendar', label: 'Calendar' }] },
  { value: 'Settings', items: [{ value: 'profile', label: 'Profile', shortcut: '⌘P' }] },
]

<Command items={groups}>
  <CommandInput placeholder="Type a command or search…" />
  <CommandEmpty>No results found.</CommandEmpty>
  <CommandList>
    {(group, index) => (
      <Fragment key={group.value}>
        {index > 0 && <CommandSeparator />}
        <CommandGroup items={group.items} heading={group.value}>
          {item => (
            <CommandItem key={item.value} value={item} onClick={() => run(item.value)}>
              {item.label}
              {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
            </CommandItem>
          )}
        </CommandGroup>
      </Fragment>
    )}
  </CommandList>
</Command>

// Flat list: pass an array of items and render them straight from CommandList.
// In a dialog: wrap the <Command> in <CommandDialog open={open} onOpenChange={setOpen}>.

Examples

Command dialog

Press ⌘K or Ctrl+K anywhere on the page.

'use client'

import * as React from 'react'
import {
  Command,
  CommandDialog,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandItem,
  CommandShortcut,
} from '@/components/ui/command'
import { Button } from '@/components/ui/button'

interface Action {
  value: string
  label: string
  shortcut?: string
}

const actions: Action[] = [
  { value: 'new-file', label: 'New file', shortcut: '⌘N' },
  { value: 'open-project', label: 'Open project…', shortcut: '⌘O' },
  { value: 'search', label: 'Search in files', shortcut: '⇧⌘F' },
  { value: 'theme', label: 'Toggle theme', shortcut: '⌘T' },
  { value: 'docs', label: 'Read the docs' },
]

export default function CommandDialogExample() {
  const [open, setOpen] = React.useState(false)
  const [last, setLast] = React.useState<string | null>(null)

  React.useEffect(() => {
    const onKeyDown = (event: KeyboardEvent) => {
      if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
        event.preventDefault()
        setOpen(current => !current)
      }
    }
    document.addEventListener('keydown', onKeyDown)
    return () => document.removeEventListener('keydown', onKeyDown)
  }, [])

  return (
    <div className="grid justify-items-center gap-3">
      <Button variant="outline" onClick={() => setOpen(true)}>
        Open command palette
        <span className="ml-2 rounded border border-border px-1.5 py-0.5 text-[10px] font-normal text-muted-foreground">⌘K</span>
      </Button>
      <p className="text-sm text-muted-foreground" aria-live="polite">
        {last ? `Ran “${last}”` : 'Press ⌘K or Ctrl+K anywhere on the page.'}
      </p>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <Command items={actions}>
          <CommandInput placeholder="Type a command or search…" />
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandList>
            {(item: Action) => (
              <CommandItem
                key={item.value}
                value={item}
                onClick={() => {
                  setLast(item.label)
                  setOpen(false)
                }}
              >
                {item.label}
                {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
              </CommandItem>
            )}
          </CommandList>
        </Command>
      </CommandDialog>
    </div>
  )
}

API Reference

NameTypeDefaultDescription
itemsItem[] | { value: string; items: Item[] }[]—The commands, flat or in groups. Objects shaped { value, label } are searched by label. Filtering is built in.
filter(item, query, itemToString?) => boolean—Replace the default match (case- and accent-insensitive "contains").
search / onSearchChangestring / (search: string) => void—Control the search text from outside.
defaultSearchstring''Initial search text (uncontrolled).
CommandList children(item, index) => ReactNode—A render function, called for each visible item (or group). Only the items that match the search are rendered.
CommandGroup items / headingItem[] / ReactNode—A group of items with a label. Pass group.items and render each item with the function child.
CommandItem valueItem—The item this row represents — pass the same object you were handed.
CommandItem onClick(event) => void—Runs on click and on Enter while the item is highlighted. Use it to perform the action.
CommandItem disabledbooleanfalseSkips the item when navigating and ignores clicks.
CommandInput aria-labelstring'Search'Accessible name of the search field. Change it to describe what is searched.
CommandEmpty——Shown only while nothing matches. Render it before CommandList.
CommandDialogDialog props + { title?, description? }—Hosts a Command in a modal Dialog. title and description are announced to screen readers but not shown.
Keyboard——Typing filters; ArrowUp and ArrowDown move the highlight, Home and End jump to the first and last item, Enter runs the highlighted item. The first match is highlighted as you type.