Command

A searchable command palette. Built on Base UI's Autocomplete primitive for filtering and keyboard navigation, and its Dialog primitive when used as a ⌘K overlay. Can also render standalone with CommandPanel, without a dialog.

Last updated August 8, 2026

CreditsModifiedPublished

Copied from shadcn/ui.

  • Added RTL support
  • Added a standalone CommandPanel for non-dialog usage
  • Added CommandFooter for keyboard-hint helpers, hidden on small screens

Overview

"use client"
 
import * as React from "react"
 
import {
  ArrowDownIcon,
  ArrowUpIcon,
  CalculatorIcon,
  CalendarIcon,
  CornerDownLeftIcon,
  CreditCardIcon,
  SettingsIcon,
  SmileIcon,
  UserIcon,
} from "lucide-react"
 
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandCollection,
  CommandDialog,
  CommandDialogPopup,
  CommandDialogTrigger,
  CommandEmpty,
  CommandFooter,
  CommandGroup,
  CommandGroupLabel,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"
import { Kbd } from "@/components/ui/kbd"
 
const groups = [
  {
    value: "Suggestions",
    items: [
      { value: "calendar", label: "Calendar", icon: CalendarIcon },
      { value: "search-emoji", label: "Search Emoji", icon: SmileIcon },
      { value: "calculator", label: "Calculator", icon: CalculatorIcon },
    ],
  },
  {
    value: "Settings",
    items: [
      { value: "profile", label: "Profile", icon: UserIcon, shortcut: "⌘P" },
      {
        value: "billing",
        label: "Billing",
        icon: CreditCardIcon,
        shortcut: "⌘B",
      },
      {
        value: "settings",
        label: "Settings",
        icon: SettingsIcon,
        shortcut: "⌘S",
      },
    ],
  },
]
 
export function CommandBasicExample() {
  const [open, setOpen] = React.useState(false)
 
  React.useEffect(() => {
    function down(event: KeyboardEvent) {
      if (event.key === "k" && (event.metaKey || event.ctrlKey)) {
        event.preventDefault()
        setOpen((value) => !value)
      }
    }
 
    document.addEventListener("keydown", down)
    return () => document.removeEventListener("keydown", down)
  }, [])
 
  return (
    <CommandDialog open={open} onOpenChange={setOpen}>
      <CommandDialogTrigger
        render={
          <Button variant="outline" className="justify-between text-muted-foreground">
            Search commands...
            <Kbd>⌘K</Kbd>
          </Button>
        }
      />
      <CommandDialogPopup>
        <Command items={groups}>
          <CommandInput placeholder="Type a command or search..." />
          <CommandList>
            <CommandEmpty>No results found.</CommandEmpty>
            {groups.map((group, index) => (
              <React.Fragment key={group.value}>
                <CommandGroup items={group.items}>
                  <CommandGroupLabel>{group.value}</CommandGroupLabel>
                  <CommandCollection>
                    {(item) => (
                      <CommandItem key={item.value} value={item.value}>
                        <item.icon />
                        {item.label}
                        {"shortcut" in item && item.shortcut && (
                          <CommandShortcut>{item.shortcut}</CommandShortcut>
                        )}
                      </CommandItem>
                    )}
                  </CommandCollection>
                </CommandGroup>
                {index < groups.length - 1 && <CommandSeparator />}
              </React.Fragment>
            ))}
          </CommandList>
          <CommandFooter>
            <div className="flex items-center gap-3">
              <span className="flex items-center gap-1">
                <Kbd>
                  <ArrowUpIcon className="size-2.5" />
                </Kbd>
                <Kbd>
                  <ArrowDownIcon className="size-2.5" />
                </Kbd>
                to navigate
              </span>
              <span className="flex items-center gap-1">
                <Kbd>
                  <CornerDownLeftIcon className="size-2.5" />
                </Kbd>
                to select
              </span>
            </div>
            <span className="flex items-center gap-1">
              <Kbd>esc</Kbd>
              to close
            </span>
          </CommandFooter>
        </Command>
      </CommandDialogPopup>
    </CommandDialog>
  )
}

Installation

$ npx shadcn@latest add https://ui.persian-labs.ir/r/command.json

Usage

import {
  Command,
  CommandCollection,
  CommandDialog,
  CommandDialogPopup,
  CommandDialogTrigger,
  CommandEmpty,
  CommandFooter,
  CommandGroup,
  CommandGroupLabel,
  CommandInput,
  CommandItem,
  CommandList,
  CommandPanel,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"
import { Button } from "@/components/ui/button"
 
const items = [
  { value: "linear", label: "Linear" },
  { value: "figma", label: "Figma" },
  { value: "slack", label: "Slack" },
]
 
export function Example() {
  return (
    <CommandDialog>
      <CommandDialogTrigger render={<Button variant="outline" />}>
        Open Command Palette
      </CommandDialogTrigger>
 
      <CommandDialogPopup>
        <Command items={items}>
          <CommandInput placeholder="Search..." />
          <CommandList>
            <CommandEmpty>No results found.</CommandEmpty>
            {items.map((item) => (
              <CommandItem key={item.value} value={item.value}>
                {item.label}
              </CommandItem>
            ))}
          </CommandList>
          <CommandFooter>Use arrow keys to navigate, Enter to select</CommandFooter>
        </Command>
      </CommandDialogPopup>
    </CommandDialog>
  )
}

Examples

Standalone panel

Render commands without a dialog by wrapping Command in CommandPanel.

"use client"
 
import { CalculatorIcon, CalendarIcon, SmileIcon } from "lucide-react"
 
import {
  Command,
  CommandEmpty,
  CommandInput,
  CommandItem,
  CommandList,
  CommandPanel,
} from "@/components/ui/command"
 
const items = [
  { value: "calendar", label: "Calendar", icon: CalendarIcon },
  { value: "search-emoji", label: "Search Emoji", icon: SmileIcon },
  { value: "calculator", label: "Calculator", icon: CalculatorIcon },
]
 
export function CommandPanelExample() {
  return (
    <CommandPanel className="w-72">
      <Command items={items}>
        <CommandInput placeholder="Type a command or search..." />
        <CommandList>
          <CommandEmpty>No results found.</CommandEmpty>
          {items.map((item) => (
            <CommandItem key={item.value} value={item.value}>
              <item.icon />
              {item.label}
            </CommandItem>
          ))}
        </CommandList>
      </Command>
    </CommandPanel>
  )
}

Groups

"use client"
 
import * as React from "react"
 
import { CreditCardIcon, SettingsIcon, UserIcon } from "lucide-react"
 
import {
  Command,
  CommandCollection,
  CommandEmpty,
  CommandGroup,
  CommandGroupLabel,
  CommandInput,
  CommandItem,
  CommandList,
  CommandPanel,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"
 
const groups = [
  {
    value: "Suggestions",
    items: [
      { value: "profile", label: "Profile", icon: UserIcon, shortcut: "⌘P" },
      {
        value: "billing",
        label: "Billing",
        icon: CreditCardIcon,
        shortcut: "⌘B",
      },
    ],
  },
  {
    value: "Settings",
    items: [
      {
        value: "settings",
        label: "Settings",
        icon: SettingsIcon,
        shortcut: "⌘S",
      },
    ],
  },
]
 
export function CommandGroupsExample() {
  return (
    <CommandPanel className="w-72">
      <Command items={groups}>
        <CommandInput placeholder="Type a command or search..." />
        <CommandList>
          <CommandEmpty>No results found.</CommandEmpty>
          {groups.map((group, index) => (
            <React.Fragment key={group.value}>
              <CommandGroup items={group.items}>
                <CommandGroupLabel>{group.value}</CommandGroupLabel>
                <CommandCollection>
                  {(item) => (
                    <CommandItem key={item.value} value={item.value}>
                      <item.icon />
                      {item.label}
                      <CommandShortcut>{item.shortcut}</CommandShortcut>
                    </CommandItem>
                  )}
                </CommandCollection>
              </CommandGroup>
              {index < groups.length - 1 && <CommandSeparator />}
            </React.Fragment>
          ))}
        </CommandList>
      </Command>
    </CommandPanel>
  )
}

RTL

No configuration needed — nest the command inside a dir="rtl" container and everything, including keyboard navigation, mirrors automatically.

"use client"
 
import * as React from "react"
 
import { FileTextIcon, SettingsIcon, UserIcon } from "lucide-react"
 
import {
  Command,
  CommandCollection,
  CommandEmpty,
  CommandGroup,
  CommandGroupLabel,
  CommandInput,
  CommandItem,
  CommandList,
  CommandPanel,
  CommandSeparator,
} from "@/components/ui/command"
 
const groups = [
  {
    value: "پیشنهادها",
    items: [
      { value: "profile", label: "پروفایل کاربری", icon: UserIcon },
      { value: "documents", label: "اسناد من", icon: FileTextIcon },
    ],
  },
  {
    value: "تنظیمات",
    items: [{ value: "settings", label: "تنظیمات حساب", icon: SettingsIcon }],
  },
]
 
export function CommandRtlExample() {
  return (
    <div dir="rtl">
      <CommandPanel className="w-72">
        <Command items={groups}>
          <CommandInput placeholder="جستجوی دستور..." />
          <CommandList>
            <CommandEmpty>موردی یافت نشد.</CommandEmpty>
            {groups.map((group, index) => (
              <React.Fragment key={group.value}>
                <CommandGroup items={group.items}>
                  <CommandGroupLabel>{group.value}</CommandGroupLabel>
                  <CommandCollection>
                    {(item) => (
                      <CommandItem key={item.value} value={item.value}>
                        <item.icon />
                        {item.label}
                      </CommandItem>
                    )}
                  </CommandCollection>
                </CommandGroup>
                {index < groups.length - 1 && <CommandSeparator />}
              </React.Fragment>
            ))}
          </CommandList>
        </Command>
      </CommandPanel>
    </div>
  )
}

API Reference

Command

API reference: Base UI Command .

CommandDialog

API reference: Base UI CommandDialog .

CommandPanel

CommandFooter