# Command

A searchable menu of commands, used inline or as a command palette in a dialog.

Command is an open-source component from suiss/ui for React. The @esuiss/ui CLI copies its source into your project, so you own the code.

Source: https://ui.suiss.app/docs/components/command

**React**

**Example**

```tsx
import {
  CalculatorIcon,
  CalendarBlankIcon,
  CreditCardIcon,
  GearIcon,
  SmileyIcon,
  UserIcon,
} from "@phosphor-icons/react"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"

function CommandItems() {
  return (
    <>
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandGroup heading="Suggestions">
        <CommandItem>
          <CalendarBlankIcon />
          Calendar
        </CommandItem>
        <CommandItem>
          <SmileyIcon />
          Search emoji
        </CommandItem>
        <CommandItem disabled>
          <CalculatorIcon />
          Calculator
        </CommandItem>
      </CommandGroup>
      <CommandSeparator />
      <CommandGroup heading="Settings">
        <CommandItem>
          <UserIcon />
          Profile
          <CommandShortcut mod>P</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <CreditCardIcon />
          Billing
          <CommandShortcut mod>B</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <GearIcon />
          Settings
          <CommandShortcut mod>S</CommandShortcut>
        </CommandItem>
      </CommandGroup>
    </>
  )
}

export default function CommandDemo() {
  return (
    <div className="w-140">
      <Command className="ring-foreground/5 shadow-md ring-1">
        <CommandInput placeholder="Type a command or search..." />
        <CommandList>
          <CommandItems />
        </CommandList>
      </Command>
    </div>
  )
}
```

Command is built on cmdk. The `Command` root filters and orders its items as people type into `CommandInput`. `CommandList` holds the results: `CommandGroup` sections with a `heading`, `CommandItem` rows, `CommandSeparator` dividers, and a `CommandEmpty` message shown when nothing matches. `CommandShortcut` displays a keyboard shortcut at the end of an item.

`CommandDialog` places a `Command` in a modal dialog for a command palette. Use a command menu for actions and navigation that people search by name. To pick a value for a form field, use a combobox instead.

## Installation

### CLI

```bash title="Terminal"
npx shadcn@latest add @esuiss/command
```

Works in any project with a `components.json`. See [Installation](https://ui.suiss.app/docs/installation#add-components) for the one-line registry setup. Or use the suiss/ui CLI:

```bash title="Terminal"
npx @esuiss/ui@latest add command
```

### Manual

1. Install the dependencies and add the [`cn` helper](https://ui.suiss.app/docs/installation#the-cn-helper):

```bash title="Terminal"
npm install @phosphor-icons/react cmdk
```

2. Add the pieces it builds on: [Dialog](https://ui.suiss.app/docs/components/dialog), `use-platform`.

3. Copy the source into `components/ui/command.tsx`:

```tsx title="components/ui/command.tsx"
"use client"

import { CheckIcon, MagnifyingGlassIcon } from "@phosphor-icons/react"
import { Command as CommandPrimitive } from "cmdk"
import type * as React from "react"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import { useModifierKey } from "@/hooks/use-platform"
import { cn } from "@/lib/utils"

function Command({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive>) {
  return (
    <CommandPrimitive
      data-slot="command"
      className={cn(
        "flex size-full flex-col overflow-hidden rounded-2xl bg-popover text-popover-foreground in-data-[slot=dialog-content]:rounded-none in-data-[slot=dialog-content]:bg-transparent",
        className
      )}
      {...props}
    />
  )
}

function CommandDialog({
  title = "Command Palette",
  description = "Search for a command to run...",
  children,
  className,
  showCloseButton = false,
  ...props
}: Omit<React.ComponentProps<typeof Dialog>, "children"> & {
  title?: string
  description?: string
  className?: string
  showCloseButton?: boolean
  children: React.ReactNode
}) {
  return (
    <Dialog {...props}>
      <DialogContent
        className={cn(
          "top-[18vh] translate-y-0 gap-0 overflow-hidden rounded-3xl! bg-popover/92 p-0 shadow-2xl ring-foreground/10 backdrop-blur-2xl backdrop-saturate-150 sm:max-w-160 dark:bg-popover/85",
          className
        )}
        showCloseButton={showCloseButton}
      >
        <DialogHeader className="sr-only">
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>{description}</DialogDescription>
        </DialogHeader>
        {children}
      </DialogContent>
    </Dialog>
  )
}

function CommandInput({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
  return (
    <div
      data-slot="command-input-wrapper"
      className="flex h-14 shrink-0 items-center gap-3 border-b border-border px-4"
    >
      <MagnifyingGlassIcon
        aria-hidden="true"
        className="size-5.5 shrink-0 text-muted-foreground"
      />
      <CommandPrimitive.Input
        data-slot="command-input"
        className={cn(
          "h-full w-full min-w-0 bg-transparent text-xl caret-primary outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        {...props}
      />
    </div>
  )
}

function CommandList({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.List>) {
  return (
    <CommandPrimitive.List
      data-slot="command-list"
      className={cn(
        "no-scrollbar max-h-80 scroll-py-1.5 overflow-x-hidden overflow-y-auto p-1.5 outline-none",
        className
      )}
      {...props}
    />
  )
}

function CommandEmpty({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
  return (
    <CommandPrimitive.Empty
      data-slot="command-empty"
      className={cn(
        "py-10 text-center text-base text-muted-foreground",
        className
      )}
      {...props}
    />
  )
}

function CommandGroup({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
  return (
    <CommandPrimitive.Group
      data-slot="command-group"
      className={cn(
        "overflow-hidden text-foreground not-first:pt-2 **:[[cmdk-group-heading]]:px-3 **:[[cmdk-group-heading]]:pt-1 **:[[cmdk-group-heading]]:pb-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-semibold **:[[cmdk-group-heading]]:text-muted-foreground",
        className
      )}
      {...props}
    />
  )
}

function CommandSeparator({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
  return (
    <CommandPrimitive.Separator
      data-slot="command-separator"
      className={cn("mx-3 my-2 h-px bg-border", className)}
      {...props}
    />
  )
}

function CommandItem({
  className,
  children,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
  return (
    <CommandPrimitive.Item
      data-slot="command-item"
      className={cn(
        "group/command-item relative flex h-10 cursor-default items-center gap-3 rounded-lg px-3 text-base outline-hidden select-none data-[disabled=true]:pointer-events-none data-selected:bg-primary data-selected:text-primary-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5 [&_svg]:text-muted-foreground data-selected:[&_svg]:text-primary-foreground data-[disabled=true]:opacity-50",
        className
      )}
      {...props}
    >
      {children}
      <CheckIcon
        className="ms-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100"
      />
    </CommandPrimitive.Item>
  )
}

function CommandShortcut({
  className,
  mod,
  children,
  ...props
}: React.ComponentProps<"span"> & { mod?: boolean }) {
  const modifier = useModifierKey(children != null)

  return (
    <span
      data-slot="command-shortcut"
      className={cn(
        "max-md:hidden ms-auto text-sm tracking-widest text-muted-foreground group-data-selected/command-item:text-primary-foreground",
        className
      )}
      {...props}
    >
      {mod && modifier}
      {children}
    </span>
  )
}

export {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandSeparator, CommandItem, CommandShortcut } from "@/components/ui/command"
```

```tsx
<div className="w-140">
  <Command className="ring-foreground/5 shadow-md ring-1">
    <CommandInput placeholder="Type a command or search..." />
    <CommandList>
      <CommandItems />
    </CommandList>
  </Command>
</div>
```

Compose `CommandInput` and `CommandList` inside `Command`, and put groups and items in the list. For a palette, wrap the `Command` in `CommandDialog` and control it with `open` and `onOpenChange`. Respond to a chosen item with its `onSelect` callback, and set `disabled` on items that are unavailable.

Set `mod` on `CommandShortcut` to prefix the shortcut with the platform modifier key: `⌘` on Apple platforms and `Ctrl+` elsewhere.

## Examples

### Empty

A command menu with no items that always shows its empty message.

**Example**

```tsx
import {
  Command,
  CommandEmpty,
  CommandInput,
  CommandList,
} from "@/components/ui/command"

export default function CommandEmptyExample() {
  return (
    <div className="w-140">
      <Command className="ring-foreground/5 shadow-md ring-1">
        <CommandInput placeholder="Search projects..." />
        <CommandList>
          <CommandEmpty>No projects found.</CommandEmpty>
        </CommandList>
      </Command>
    </div>
  )
}
```

### Dialog

A command palette in a dialog, opened from a button, that closes with Escape and returns focus to the button.

**Example**

```tsx
import {
  CalculatorIcon,
  CalendarBlankIcon,
  CreditCardIcon,
  GearIcon,
  SmileyIcon,
  UserIcon,
} from "@phosphor-icons/react"
import * as React from "react"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"

function CommandItems() {
  return (
    <>
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandGroup heading="Suggestions">
        <CommandItem>
          <CalendarBlankIcon />
          Calendar
        </CommandItem>
        <CommandItem>
          <SmileyIcon />
          Search emoji
        </CommandItem>
        <CommandItem disabled>
          <CalculatorIcon />
          Calculator
        </CommandItem>
      </CommandGroup>
      <CommandSeparator />
      <CommandGroup heading="Settings">
        <CommandItem>
          <UserIcon />
          Profile
          <CommandShortcut mod>P</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <CreditCardIcon />
          Billing
          <CommandShortcut mod>B</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <GearIcon />
          Settings
          <CommandShortcut mod>S</CommandShortcut>
        </CommandItem>
      </CommandGroup>
    </>
  )
}

function CommandDialogExample({
  defaultOpen = false,
}: {
  defaultOpen?: boolean
}) {
  const [open, setOpen] = React.useState(defaultOpen)

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Open command palette
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <Command>
          <CommandInput placeholder="Type a command or search..." />
          <CommandList>
            <CommandItems />
          </CommandList>
        </Command>
      </CommandDialog>
    </>
  )
}

export default function CommandDialogDemo() {
  return (
    <div className="w-140">
      <CommandDialogExample />
    </div>
  )
}
```

### Dialog open

A command palette that is open when the page loads.

**Example**

```tsx
import {
  CalculatorIcon,
  CalendarBlankIcon,
  CreditCardIcon,
  GearIcon,
  SmileyIcon,
  UserIcon,
} from "@phosphor-icons/react"
import * as React from "react"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"

function CommandItems() {
  return (
    <>
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandGroup heading="Suggestions">
        <CommandItem>
          <CalendarBlankIcon />
          Calendar
        </CommandItem>
        <CommandItem>
          <SmileyIcon />
          Search emoji
        </CommandItem>
        <CommandItem disabled>
          <CalculatorIcon />
          Calculator
        </CommandItem>
      </CommandGroup>
      <CommandSeparator />
      <CommandGroup heading="Settings">
        <CommandItem>
          <UserIcon />
          Profile
          <CommandShortcut mod>P</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <CreditCardIcon />
          Billing
          <CommandShortcut mod>B</CommandShortcut>
        </CommandItem>
        <CommandItem>
          <GearIcon />
          Settings
          <CommandShortcut mod>S</CommandShortcut>
        </CommandItem>
      </CommandGroup>
    </>
  )
}

function CommandDialogExample({
  defaultOpen = false,
}: {
  defaultOpen?: boolean
}) {
  const [open, setOpen] = React.useState(defaultOpen)

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Open command palette
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <Command>
          <CommandInput placeholder="Type a command or search..." />
          <CommandList>
            <CommandItems />
          </CommandList>
        </Command>
      </CommandDialog>
    </>
  )
}

export default function CommandDialogOpen() {
  return (
    <div className="w-140">
      <CommandDialogExample defaultOpen />
    </div>
  )
}
```

## API Reference

- `Command`
- `CommandInput`
- `CommandList`
  - `CommandEmpty`

### Command

The root that filters and manages the items.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive>`.

### CommandDialog

A modal dialog that presents a command menu as a palette.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | `"Command Palette"` | The dialog's accessible title. It is visually hidden. |
| `description` | `string` | `"Search for a command to run..."` | The dialog's accessible description. It is visually hidden. |
| `className` | `string` | - | Classes applied to the dialog's content panel. |
| `showCloseButton` | `boolean` | `false` | Shows the dialog's close button. |
| `children` | `React.ReactNode` | Required | The dialog's content, typically a `Command`. |

Also accepts the props of `React.ComponentProps<typeof Dialog>`.

### CommandInput

The search field, shown with a magnifying glass icon.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.Input>`.

### CommandList

The scrollable container for results.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.List>`.

### CommandEmpty

Content shown when no items match the search.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.Empty>`.

### CommandGroup

A section of related items with an optional heading.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.Group>`.

### CommandSeparator

A divider between groups.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.Separator>`.

### CommandItem

A selectable command.

Also accepts the props of `React.ComponentProps<typeof CommandPrimitive.Item>`.

### CommandShortcut

Displays a keyboard shortcut at the end of an item.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `mod` | `boolean` | - | Prefixes the shortcut with the platform modifier key, `⌘` on Apple platforms and `Ctrl+` elsewhere. |

Also accepts the props of `React.ComponentProps<"span">`.

## Accessibility

- The input has the `combobox` role and items have the `option` role. The highlighted item sets `aria-selected` and disabled items set `aria-disabled`.
- The first item is highlighted by default. Arrow keys move the highlight and skip disabled items; Enter selects the highlighted item.
- `CommandDialog` renders a `dialog` named by its `title`, moves focus inside when it opens, closes with Escape, and returns focus to the element that opened it.
- `CommandShortcut` is hidden on small screens.

## Notes

- Styling hooks: `data-slot` values `command`, `command-input-wrapper`, `command-input`, `command-list`, `command-empty`, `command-group`, `command-separator`, `command-item` and `command-shortcut`.
- The highlighted item gets `data-selected` and is filled with the `primary` color. Disabled items get `data-disabled="true"`.
- An item with `data-checked="true"` shows a check mark, unless it contains a `CommandShortcut`.
- Inside a dialog, `Command` drops its own background and rounded corners. The palette uses a translucent, blurred `popover` background.

