# Command

An accessible React command menu for Next.js and Tailwind CSS: a ⌘K palette that filters and ranks as you type, with groups, shortcuts and a gliding highlight.

Source: https://ui.fewtone.com/components/command

## Installation

```bash
npx shadcn@latest add https://ui.fewtone.com/r/command.json
```

## Usage

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

export function Palette() {
  return (
    <CommandDialog shortcut="k">
      <CommandInput placeholder="Type a command or search…" />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Pages">
          <CommandItem onSelect={() => {}}>Dashboard</CommandItem>
          <CommandItem keywords={["preferences"]}>Settings</CommandItem>
        </CommandGroup>
      </CommandList>
    </CommandDialog>
  )
}
```

## API reference

### Command

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | – | The search field's accessible name. Defaults to its placeholder. |
| `filter` | `(text: string, search: string, keywords?: string[]) => number` | – | Scores an item against the search, from 0 (hidden) to 1 (exact). The default ranks exact matches, then word starts, then anywhere, then keywords, then letters in order. Export: commandFilter. |
| `shouldFilter` | `boolean` | `true` | Set false to filter yourself, for example results fetched as you type. |
| `loop` | `boolean` | `false` | ArrowDown on the last item goes back to the first, and ArrowUp the other way. |
| `value` | `string` | – | The highlighted item's value, when you control it. |
| `defaultValue` | `string` | – | The item highlighted at first. |
| `onValueChange` | `(value: string) => void` | – | Called when the highlight moves to another item. |
| `search` | `string` | – | The search, when you control it here (CommandInput's value does the same). |
| `onSearchChange` | `(search: string) => void` | – | Called with the search as it changes. |

### CommandInput

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | – | The search, when you control it. |
| `onValueChange` | `(search: string) => void` | – | Called with the search as it changes. |
| `placeholder` | `string` | – | The hint in the empty field. |

### CommandList

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `"Results"` | The list's accessible name. |

### CommandEmpty

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` | `"No results found."` | The message. |

### CommandGroup

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `heading` | `ReactNode` | – | The heading, which also names the group. |

### CommandItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `onSelect` | `(value: string) => void` | – | Runs the item, with its value. |
| `value` | `string` | – | What onSelect receives. Defaults to the item's text; keep it unique. |
| `keywords` | `string[]` | – | More words the search matches, for example “preferences” for Settings. |
| `textValue` | `string` | – | The text the search matches, when the content isn't plain text. |
| `disabled` | `boolean` | `false` | Skips the item. |
| `forceMount` | `boolean` | `false` | Always shown, whatever the search. |

### CommandShortcut

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### CommandSeparator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `alwaysRender` | `boolean` | `false` | Keep it while searching. |

### CommandDialog

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `shortcut` | `string` | – | Opens and closes it with ⌘ (Ctrl on Windows and Linux) plus this key, for example “k”. |
| `open` | `boolean` | – | Whether it's open, when you control it. |
| `defaultOpen` | `boolean` | `false` | Whether it starts open. |
| `onOpenChange` | `(open: boolean) => void` | – | Called when it opens or closes. Close it from an item's onSelect to run and dismiss. |
| `title` | `string` | `"Command palette"` | Names the dialog for screen readers. |
| `description` | `string` | `"Search for a command to run."` | Describes the dialog for screen readers. |
| `showCloseButton` | `boolean` | `false` | Shows a close button in the corner. Escape and the backdrop close it either way. |

**When to use it:** Use Command for a searchable list of pages and actions, inline or as a ⌘K palette (CommandDialog). Use Combobox to pick a form value from a long list, Dropdown Menu for a short menu of actions on a button, and Select for a short list of values.
**Built on:** Radix Dialog.
**Accessibility pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/
**npm packages (installed by the CLI):** lucide-react@^1.52.0, motion@^14.0.0.
**Installs these FewTone UI components with it:** `dialog`.

## Examples

### Command menu

Type to filter: the best matches rise to the top, groups with nothing left hide, and the list glides to its new height. The arrow keys move the highlight, Home and End jump, and Enter runs the item. Try “stg” or “invoices”.

```tsx
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command";
import {
  CalculatorIcon,
  CalendarIcon,
  CreditCardIcon,
  SettingsIcon,
  SmileIcon,
  UserIcon,
} from "lucide-react";

/*
 * A command menu on the page: two groups with icons and shortcuts, a separator and a disabled item. Typing
 * filters it. It sits at the top of the preview, so the field stays put while the list's height glides.
 */
export default function CommandDefault() {
  return (
    <div className="flex w-full justify-center self-start">
      <Command label="Command menu" className="max-w-md border border-border shadow-md">
        <CommandInput placeholder="Type a command or search…" />
        <CommandList>
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandGroup heading="Suggestions">
            <CommandItem keywords={["schedule", "events"]}>
              <CalendarIcon />
              Calendar
            </CommandItem>
            <CommandItem keywords={["smiley", "emoticon"]}>
              <SmileIcon />
              Search emoji
            </CommandItem>
            <CommandItem disabled>
              <CalculatorIcon />
              Calculator
            </CommandItem>
          </CommandGroup>
          <CommandSeparator />
          <CommandGroup heading="Settings">
            <CommandItem keywords={["account"]}>
              <UserIcon />
              Profile
              <CommandShortcut>⌘P</CommandShortcut>
            </CommandItem>
            <CommandItem keywords={["payment", "invoices"]}>
              <CreditCardIcon />
              Billing
              <CommandShortcut>⌘B</CommandShortcut>
            </CommandItem>
            <CommandItem keywords={["preferences"]}>
              <SettingsIcon />
              Settings
              <CommandShortcut>⌘S</CommandShortcut>
            </CommandItem>
          </CommandGroup>
        </CommandList>
      </Command>
    </div>
  );
}
```

### Command palette

CommandDialog puts it in a dialog near the top of the screen. Open it from the button or with ⌘J (Ctrl J on Windows and Linux); this site already uses ⌘K for its own search. Escape or the backdrop closes it.

```tsx
"use client";

import { Button } from "@/components/ui/button";
import {
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command";
import {
  FolderIcon,
  LayoutDashboardIcon,
  MoonIcon,
  PlusIcon,
  SearchIcon,
  SettingsIcon,
  UserPlusIcon,
} from "lucide-react";
import { useState, useSyncExternalStore } from "react";

const noop = () => () => {};
/** ⌘ on a Mac, Ctrl elsewhere: read on the client; the server assumes a Mac and the client corrects it */
function useIsMac() {
  return useSyncExternalStore(
    noop,
    () => /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent),
    () => true,
  );
}

/*
 * The palette in a dialog, opened from a button or with ⌘J (Ctrl J). This site already uses ⌘K for its own
 * search, so the example takes J; your app would pass shortcut="k". The caps light up while the keys are
 * held. Running a command closes it, so it's controlled.
 */
export default function CommandPalette() {
  const [open, setOpen] = useState(false);
  const mac = useIsMac();
  const run = () => setOpen(false);

  return (
    <>
      <Button
        variant="outline"
        onClick={() => setOpen(true)}
        aria-keyshortcuts="Meta+J Control+J"
        className="w-64 justify-start ps-3 pe-2 text-muted-foreground"
      >
        <SearchIcon />
        <span className="flex-1 text-start">Search…</span>
        <kbd aria-hidden className="font-sans text-xs font-medium text-muted-foreground">
          {mac ? "⌘J" : "Ctrl J"}
        </kbd>
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen} shortcut="j">
        <CommandInput placeholder="Type a command or search…" />
        <CommandList>
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandGroup heading="Pages">
            <CommandItem onSelect={run} keywords={["home", "overview"]}>
              <LayoutDashboardIcon />
              Dashboard
            </CommandItem>
            <CommandItem onSelect={run}>
              <FolderIcon />
              Projects
            </CommandItem>
            <CommandItem onSelect={run} keywords={["preferences", "account"]}>
              <SettingsIcon />
              Settings
            </CommandItem>
          </CommandGroup>
          <CommandSeparator />
          <CommandGroup heading="Actions">
            <CommandItem onSelect={run} keywords={["create", "add"]}>
              <PlusIcon />
              New project
              <CommandShortcut>⌘N</CommandShortcut>
            </CommandItem>
            <CommandItem onSelect={run} keywords={["team", "members", "share"]}>
              <UserPlusIcon />
              Invite people
            </CommandItem>
            <CommandItem onSelect={run} keywords={["theme", "light", "appearance"]}>
              <MoonIcon />
              Switch to dark mode
            </CommandItem>
          </CommandGroup>
        </CommandList>
      </CommandDialog>
    </>
  );
}
```

## Related

- [Combobox](https://ui.fewtone.com/components/combobox.md): An accessible React combobox for Next.js and Tailwind CSS: type in the field to filter and pick one option, or several as chips, with a gliding highlight.
- [Dialog](https://ui.fewtone.com/components/dialog.md): An accessible React dialog for Next.js and Tailwind CSS: a modal window that grows out of its trigger, keeps focus inside and returns it, built on Radix Dialog.
