---
title: Command
description: "Fast, composable command palette."
---

```tsx
import * as stylex from '@stylexjs/stylex';

import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandShortcut,
} from '@/components/ui/command';
import { ring } from '@/lib/stylex-utils';
import { container } from '@/lib/constants.stylex';
import { shadow } from '@/lib/tokens.stylex';

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

type CommandEntry = (typeof commands)[number];

export default function CommandDemo() {
  return (
    <Command
      items={commands}
      itemToStringLabel={(item: CommandEntry) => item.label}
      style={[styles.root, ring({ shadow: shadow.md })]}
    >
      <CommandInput placeholder="Type a command or search…" />
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandList>
        {(item: CommandEntry) => (
          <CommandItem key={item.value} value={item}>
            {item.label}
            {item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
          </CommandItem>
        )}
      </CommandList>
    </Command>
  );
}

const styles = stylex.create({
  root: {
    maxWidth: container.lg,
  },
});
```

## Install

```bash
npx shadcn@latest add @madeui/command
```

## Usage

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

## Composition

```tsx
<Command items={items}>
  <CommandInput />
  <CommandEmpty />
  <CommandList>
    {(item) => <CommandItem value={item} />}
  </CommandList>
</Command>
```

## Groups

```tsx
import * as React from 'react';

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

function CalendarIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox={`0 0 16 16`}
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
    >
      <rect x="2" y="3" width="12" height="11" rx="1.5" />
      <path d={`M2 6.5h12M5 1.5v3M11 1.5v3`} />
    </svg>
  );
}

function SmileIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox={`0 0 16 16`}
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
    >
      <circle cx="8" cy="8" r="6.5" />
      <path d={`M5.5 9.5c.6.8 1.4 1.2 2.5 1.2s1.9-.4 2.5-1.2`} />
      <path d={`M6 6h.01M10 6h.01`} />
    </svg>
  );
}

function UserIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox={`0 0 16 16`}
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
    >
      <circle cx="8" cy="5.5" r="2.5" />
      <path d={`M2.5 14c.8-2.8 3-4.5 5.5-4.5s4.7 1.7 5.5 4.5`} />
    </svg>
  );
}

function CardIcon() {
  return (
    <svg
      width="16"
      height="16"
      viewBox={`0 0 16 16`}
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
    >
      <rect x="1.5" y="4" width="13" height="9" rx="1.5" />
      <path d={`M1.5 7h13`} />
    </svg>
  );
}

const commandGroups = [
  {
    value: 'suggestions',
    label: 'Suggestions',
    items: [
      { value: 'calendar', label: 'Calendar', icon: <CalendarIcon /> },
      { value: 'search-emoji', label: 'Search emoji', icon: <SmileIcon /> },
    ],
  },
  {
    value: 'settings',
    label: 'Settings',
    items: [
      {
        value: 'profile',
        label: 'Profile',
        icon: <UserIcon />,
        shortcut: '⌘P',
      },
      { value: 'billing', label: 'Billing', icon: <CardIcon />, shortcut: '⌘B' },
    ],
  },
];

export default function CommandGroups() {
  return (
    <Command items={commandGroups}>
      <CommandInput placeholder="Type a command or search…" />
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandList>
        {(group: (typeof commandGroups)[number]) => (
          <React.Fragment key={group.value}>
            <CommandGroup heading={group.label}>
              {group.items.map((item) => (
                <CommandItem key={item.value} value={item}>
                  {item.icon}
                  {item.label}
                  {'shortcut' in item && item.shortcut && (
                    <CommandShortcut>{item.shortcut}</CommandShortcut>
                  )}
                </CommandItem>
              ))}
            </CommandGroup>
            {group.value !==
              commandGroups[commandGroups.length - 1].value && (
              <CommandSeparator />
            )}
          </React.Fragment>
        )}
      </CommandList>
    </Command>
  );
}
```

## Scrollable

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

const fruits = [
  'Apple', 'Apricot', 'Banana', 'Blackberry', 'Blueberry', 'Cantaloupe',
  'Cherry', 'Clementine', 'Coconut', 'Cranberry', 'Date', 'Dragonfruit',
  'Elderberry', 'Fig', 'Grape', 'Grapefruit', 'Guava', 'Honeydew', 'Kiwi',
  'Lemon', 'Lime', 'Lychee', 'Mango', 'Mandarin', 'Nectarine', 'Orange',
  'Papaya', 'Passionfruit', 'Peach', 'Pear', 'Persimmon', 'Pineapple',
  'Plum', 'Pomegranate', 'Raspberry', 'Star fruit', 'Strawberry',
  'Tangerine', 'Watermelon',
].map((label) => ({ label, value: label }));

export default function CommandScrollable() {
  return (
    <Command items={fruits} itemToStringLabel={(item) => item.label}>
      <CommandInput placeholder="Search fruit…" />
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandList>
        {(item: (typeof fruits)[number]) => (
          <CommandItem key={item.value} value={item}>
            {item.label}
          </CommandItem>
        )}
      </CommandList>
    </Command>
  );
}
```

## Keyboard shortcut

Open the palette with **⌘K** / **Ctrl K** using the `useHotkey` helper
(`npx shadcn@latest add @madeui/use-hotkey`).

```tsx
'use client';

import * as React from 'react';

import { Button } from '@/components/ui/button';
import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command';
import { Kbd, KbdGroup } from '@/components/ui/kbd';
import { useHotkey } from '@/lib/use-hotkey';

const commands = [
  { value: 'calendar', label: 'Calendar' },
  { value: 'search-emoji', label: 'Search emoji' },
  { value: 'calculator', label: 'Calculator' },
];

type CommandEntry = (typeof commands)[number];

export default function CommandDialogHotkey() {
  const [open, setOpen] = React.useState(false);
  useHotkey('k', () => setOpen((value) => !value));

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Open command palette
        <KbdGroup>
          <Kbd>⌘</Kbd>
          <Kbd>K</Kbd>
        </KbdGroup>
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <Command
          items={commands}
          itemToStringLabel={(item: CommandEntry) => item.label}
        >
          <CommandInput placeholder="Type a command or search…" />
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandList>
            {(item: CommandEntry) => (
              <CommandItem
                key={item.value}
                value={item}
                onClick={() => setOpen(false)}
              >
                {item.label}
              </CommandItem>
            )}
          </CommandList>
        </Command>
      </CommandDialog>
    </>
  );
}
```

## API reference

Built on [Base UI Autocomplete](https://base-ui.com/react/components/autocomplete) in `inline open` mode — the filtered list renders in place with no popup, like a command palette, with no extra dependency. Pass `items` to `Command`; filtering and highlight ship with the primitive, and `CommandList` accepts a render function over the filtered items. All other props are forwarded to the Base UI `Root` (`filter`, `onValueChange`, `itemToStringLabel`, …); see the [Base UI Autocomplete API reference](https://base-ui.com/react/components/autocomplete#api-reference).

### CommandDialog

Wraps the palette in our `Dialog` (installed as a dependency), positioned at the top third with no close button.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | `'Command Palette'` | Screen-reader-only dialog title. |
| `description` | `string` | `'Search for a command to run…'` | Screen-reader-only description. |

### CommandGroup

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `heading` | `ReactNode` | — | Renders a muted group label above the items. |

Every part accepts a `style` prop (`StyleXStyles`, merged last).
