# Shadcn Command

> Free shadcn/ui command component for React — the cmdk-powered command menu and ⌘K palette. Nested pages, custom filtering, async search, and a Popover combobox. The examples official shadcn never shipped.

Source: https://designrevision.com/components/command

The **Shadcn Command** is the command menu and ⌘K palette — the canonical <a href="https://ui.shadcn.com/docs/components/command" rel="nofollow">shadcn/ui</a> command built on <a href="https://cmdk.paco.me/" rel="nofollow">**cmdk**</a>, with fuzzy search, keyboard navigation, grouping, and a `CommandDialog` for the palette. Official ships a basic menu and a ⌘K demo; the examples below cover what real apps need — **nested pages**, custom filtering, async search, and a [Popover](/components/popover) combobox.

## Built on cmdk

The Command is a thin, styled wrapper over <a href="https://cmdk.paco.me/" rel="nofollow">**cmdk**</a>, Paco Coursey's command-menu library. cmdk owns the hard parts — **fuzzy filtering and ranking**, full **keyboard navigation**, grouping, and the accessibility wiring — so the shadcn layer only adds Tailwind styling and your design tokens. Install it once:

```bash
npm install cmdk
```

Every example below — the palette, nested pages, custom filters, async search, the combobox — is cmdk surfaced through the shadcn parts (`Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandSeparator`, `CommandShortcut`). (Prefer a heavier, action-registry approach? Libraries like **kbar** exist — but for most apps cmdk + this Command is lighter and matches your design system.)

## The ⌘K command palette

The palette is the marquee use. Wrap your list in `CommandDialog`, hold its `open` state, and register a global keydown listener:

```tsx
React.useEffect(() => {
  const down = (e: KeyboardEvent) => {
    if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
      e.preventDefault()
      setOpen((open) => !open)
    }
  }
  document.addEventListener("keydown", down)
  return () => document.removeEventListener("keydown", down)
}, [])
```

`CommandDialog` renders the Command inside a [Dialog](/components/dialog) with an `sr-only` title and description so it's announced to screen readers. The ⌘K command palette example is the complete version, with a [Kbd](/components/kbd) badge in the trigger.

## Inline, Dialog & Combobox

The same Command renders three ways depending on its container:

- **Inline** — drop `Command` straight into the page for an always-visible menu (the Command menu example).
- **Dialog** — wrap it in `CommandDialog` for the ⌘K palette.
- **Combobox** — put it inside a [Popover](/components/popover) anchored to a button for a searchable select (the Combobox example).

## Custom filtering & keywords

cmdk filters on each item's value by default. To match **synonyms**, add a `keywords` array to a `CommandItem`; to control ranking yourself, pass a `filter` to `Command`:

```tsx
<Command filter={(value, search, keywords) => /* return a score, 0 = hide */}>
```

The Custom filter & keywords example makes searching "appearance" surface "Toggle theme".

## Nested pages (sub-commands)

Real palettes drill in — "Change theme…" opens a Light/Dark/System sub-list. Keep a **stack of page names** in state: render root items when it's empty, a sub-page's items when its name is on top, and push the next page from `onSelect`. Pop on Escape or on Backspace when the search is empty. The Nested pages example is the full pattern.

## Async / server-side search

For server search, set `shouldFilter={false}` so cmdk stops filtering locally, drive `CommandInput` as a controlled value, debounce a request, and render the results you receive — with a loading row in between. The Async / server search example simulates the full round-trip.

## Keyboard & accessibility

cmdk handles arrow-key navigation, Enter to select, and type-ahead out of the box; items expose `data-selected` / `data-disabled` for styling. Always give `CommandDialog` a title (it's `sr-only` by default) so the palette is announced. The Keyboard footer example adds visible [Kbd](/components/kbd) hints — ↵ to select, ↑↓ to navigate, esc to close.

## Theming

The Command reads your design tokens — `--popover`, `--accent` (the highlighted item), `--muted-foreground` (headings and shortcuts) — so it follows your theme, including dark mode, with no overrides.

## Installation

### command

**Install:**

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

**Dependencies:** cmdk, lucide-react, utils, dialog

**Usage & accessibility:** A cmdk-based searchable list. Composes from Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, and CommandShortcut. CommandDialog wraps the list in a Dialog for a ⌘K palette (accepts title/description for screen readers and showCloseButton); pair it with a keydown listener on metaKey+k. Set shouldFilter={false} on Command for server-side search.

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

import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
import { SearchIcon } from "lucide-react"

import { cn } from "@/lib/utils"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"

function Command({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive>) {
  return (
    <CommandPrimitive
      data-slot="command"
      className={cn(
        "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
        className
      )}
      {...props}
    />
  )
}

function CommandDialog({
  title = "Command Palette",
  description = "Search for a command to run...",
  children,
  className,
  showCloseButton = true,
  ...props
}: React.ComponentProps<typeof Dialog> & {
  title?: string
  description?: string
  className?: string
  showCloseButton?: boolean
}) {
  return (
    <Dialog {...props}>
      <DialogHeader className="sr-only">
        <DialogTitle>{title}</DialogTitle>
        <DialogDescription>{description}</DialogDescription>
      </DialogHeader>
      <DialogContent
        className={cn("overflow-hidden p-0", className)}
        showCloseButton={showCloseButton}
      >
        <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
          {children}
        </Command>
      </DialogContent>
    </Dialog>
  )
}

function CommandInput({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
  return (
    <div
      data-slot="command-input-wrapper"
      className="flex h-9 items-center gap-2 border-b px-3"
    >
      <SearchIcon className="size-4 shrink-0 opacity-50" />
      <CommandPrimitive.Input
        data-slot="command-input"
        className={cn(
          "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden 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(
        "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
        className
      )}
      {...props}
    />
  )
}

function CommandEmpty({
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
  return (
    <CommandPrimitive.Empty
      data-slot="command-empty"
      className="py-6 text-center text-sm"
      {...props}
    />
  )
}

function CommandGroup({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
  return (
    <CommandPrimitive.Group
      data-slot="command-group"
      className={cn(
        "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
        className
      )}
      {...props}
    />
  )
}

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

function CommandItem({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
  return (
    <CommandPrimitive.Item
      data-slot="command-item"
      className={cn(
        "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
        className
      )}
      {...props}
    />
  )
}

function CommandShortcut({
  className,
  ...props
}: React.ComponentProps<"span">) {
  return (
    <span
      data-slot="command-shortcut"
      className={cn(
        "text-muted-foreground ml-auto text-xs tracking-widest",
        className
      )}
      {...props}
    />
  )
}

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

## Examples

### Command menu

An inline menu — grouped items with icons and shortcuts, a separator, a disabled item, and a no-results state.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-demo-01
```

**Dependencies:** lucide-react, command

```tsx
// components/ui/command-demo-01.tsx
import {
  CalculatorIcon,
  CalendarIcon,
  CreditCardIcon,
  SettingsIcon,
  SmileIcon,
  UserIcon,
} from "lucide-react"

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

export default function CommandDemo01() {
  return (
    <Command className="rounded-lg border shadow-md md:min-w-[450px]">
      <CommandInput placeholder="Type a command or search…" />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Suggestions">
          <CommandItem>
            <CalendarIcon />
            <span>Calendar</span>
          </CommandItem>
          <CommandItem>
            <SmileIcon />
            <span>Search Emoji</span>
          </CommandItem>
          <CommandItem disabled>
            <CalculatorIcon />
            <span>Calculator</span>
          </CommandItem>
        </CommandGroup>
        <CommandSeparator />
        <CommandGroup heading="Settings">
          <CommandItem>
            <UserIcon />
            <span>Profile</span>
            <CommandShortcut>⌘P</CommandShortcut>
          </CommandItem>
          <CommandItem>
            <CreditCardIcon />
            <span>Billing</span>
            <CommandShortcut>⌘B</CommandShortcut>
          </CommandItem>
          <CommandItem>
            <SettingsIcon />
            <span>Settings</span>
            <CommandShortcut>⌘S</CommandShortcut>
          </CommandItem>
        </CommandGroup>
      </CommandList>
    </Command>
  )
}
```

---

### ⌘K command palette

The keyboard-driven palette — `CommandDialog` opened with a **⌘K / Ctrl+K** keydown listener, with a [Kbd](/components/kbd) hint in the trigger.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-dialog-01
```

**Dependencies:** lucide-react, command, button, kbd

```tsx
// components/ui/command-dialog-01.tsx
"use client"

import * as React from "react"
import {
  CalendarIcon,
  CreditCardIcon,
  SettingsIcon,
  SmileIcon,
  UserIcon,
} from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command"
import { Kbd } from "@/components/ui/kbd"

export default function CommandDialog01() {
  const [open, setOpen] = React.useState(false)

  React.useEffect(() => {
    const down = (e: KeyboardEvent) => {
      if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
        e.preventDefault()
        setOpen((open) => !open)
      }
    }
    document.addEventListener("keydown", down)
    return () => document.removeEventListener("keydown", down)
  }, [])

  const runCommand = React.useCallback(() => setOpen(false), [])

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        <span className="text-muted-foreground">Search…</span>
        <Kbd className="ml-2">⌘K</Kbd>
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <CommandInput placeholder="Type a command or search…" />
        <CommandList>
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandGroup heading="Suggestions">
            <CommandItem onSelect={runCommand}>
              <CalendarIcon />
              <span>Calendar</span>
            </CommandItem>
            <CommandItem onSelect={runCommand}>
              <SmileIcon />
              <span>Search Emoji</span>
            </CommandItem>
          </CommandGroup>
          <CommandSeparator />
          <CommandGroup heading="Settings">
            <CommandItem onSelect={runCommand}>
              <UserIcon />
              <span>Profile</span>
              <CommandShortcut>⌘P</CommandShortcut>
            </CommandItem>
            <CommandItem onSelect={runCommand}>
              <CreditCardIcon />
              <span>Billing</span>
              <CommandShortcut>⌘B</CommandShortcut>
            </CommandItem>
            <CommandItem onSelect={runCommand}>
              <SettingsIcon />
              <span>Settings</span>
              <CommandShortcut>⌘S</CommandShortcut>
            </CommandItem>
          </CommandGroup>
        </CommandList>
      </CommandDialog>
    </>
  )
}
```

---

### Nested pages

Items push **sub-pages** onto a stack; Backspace on an empty search pops back — the cmdk multi-level pattern.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-nested-01
```

**Dependencies:** command

```tsx
// components/ui/command-nested-01.tsx
"use client"

import * as React from "react"

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

export default function CommandNested01() {
  const [pages, setPages] = React.useState<string[]>([])
  const [search, setSearch] = React.useState("")
  const page = pages[pages.length - 1]

  const push = (next: string) => {
    setPages((prev) => [...prev, next])
    setSearch("")
  }

  return (
    <Command
      className="rounded-lg border shadow-md md:min-w-[450px]"
      onKeyDown={(e) => {
        if (pages.length > 0 && (e.key === "Escape" || (e.key === "Backspace" && !search))) {
          e.preventDefault()
          setPages((prev) => prev.slice(0, -1))
        }
      }}
    >
      <CommandInput
        value={search}
        onValueChange={setSearch}
        placeholder={page ? `Search ${page}…` : "Type a command — Backspace to go back…"}
      />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        {!page && (
          <CommandGroup heading="Home">
            <CommandItem onSelect={() => push("projects")}>Search projects…</CommandItem>
            <CommandItem onSelect={() => push("teams")}>Join a team…</CommandItem>
            <CommandItem onSelect={() => push("theme")}>Change theme…</CommandItem>
          </CommandGroup>
        )}
        {page === "projects" && (
          <CommandGroup heading="Projects">
            <CommandItem>Acme Marketing Site</CommandItem>
            <CommandItem>Internal Dashboard</CommandItem>
            <CommandItem>Mobile App</CommandItem>
          </CommandGroup>
        )}
        {page === "teams" && (
          <CommandGroup heading="Teams">
            <CommandItem>Engineering</CommandItem>
            <CommandItem>Design</CommandItem>
            <CommandItem>Marketing</CommandItem>
          </CommandGroup>
        )}
        {page === "theme" && (
          <CommandGroup heading="Theme">
            <CommandItem>Light</CommandItem>
            <CommandItem>Dark</CommandItem>
            <CommandItem>System</CommandItem>
          </CommandGroup>
        )}
      </CommandList>
    </Command>
  )
}
```

---

### Custom filter & keywords

Match items by aliases with a custom `filter` prop and per-item `keywords` — searching "appearance" finds "Toggle theme".

**Install:**

```bash
npx shadcn@latest add @designrevision/command-filter-01
```

**Dependencies:** command

```tsx
// components/ui/command-filter-01.tsx
"use client"

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

export default function CommandFilter01() {
  return (
    <Command
      className="rounded-lg border shadow-md md:min-w-[450px]"
      filter={(value, search, keywords) => {
        const haystack = `${value} ${(keywords ?? []).join(" ")}`.toLowerCase()
        return haystack.includes(search.toLowerCase()) ? 1 : 0
      }}
    >
      <CommandInput placeholder='Try "appearance" or "logout"…' />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Commands">
          <CommandItem
            value="Toggle theme"
            keywords={["appearance", "dark", "light", "mode"]}
          >
            Toggle theme
          </CommandItem>
          <CommandItem value="Sign out" keywords={["logout", "exit", "leave"]}>
            Sign out
          </CommandItem>
          <CommandItem
            value="Open settings"
            keywords={["preferences", "config", "options"]}
          >
            Open settings
          </CommandItem>
          <CommandItem
            value="Invite member"
            keywords={["add", "teammate", "user"]}
          >
            Invite member
          </CommandItem>
        </CommandGroup>
      </CommandList>
    </Command>
  )
}
```

---

### Async / server search

Server-side search with `shouldFilter={false}`, a debounced request, and a loading state — you own the results.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-async-01
```

**Dependencies:** command

```tsx
// components/ui/command-async-01.tsx
"use client"

import * as React from "react"

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

const FRAMEWORKS = [
  "Next.js",
  "React",
  "Vue",
  "Svelte",
  "Angular",
  "Solid",
  "Astro",
  "Remix",
  "Nuxt",
  "Qwik",
]

export default function CommandAsync01() {
  const [query, setQuery] = React.useState("")
  const [results, setResults] = React.useState<string[]>([])
  const [loading, setLoading] = React.useState(false)

  React.useEffect(() => {
    if (!query) {
      setResults([])
      setLoading(false)
      return
    }
    // Simulate a debounced server request.
    setLoading(true)
    const id = setTimeout(() => {
      setResults(
        FRAMEWORKS.filter((f) => f.toLowerCase().includes(query.toLowerCase()))
      )
      setLoading(false)
    }, 500)
    return () => clearTimeout(id)
  }, [query])

  return (
    <Command
      shouldFilter={false}
      className="rounded-lg border shadow-md md:min-w-[450px]"
    >
      <CommandInput
        value={query}
        onValueChange={setQuery}
        placeholder="Search frameworks (simulated fetch)…"
      />
      <CommandList>
        {loading && (
          <div className="py-6 text-center text-sm text-muted-foreground">
            Searching…
          </div>
        )}
        {!loading && query && results.length === 0 && (
          <CommandEmpty>No results found.</CommandEmpty>
        )}
        {!loading && results.length > 0 && (
          <CommandGroup heading="Frameworks">
            {results.map((framework) => (
              <CommandItem key={framework} value={framework}>
                {framework}
              </CommandItem>
            ))}
          </CommandGroup>
        )}
      </CommandList>
    </Command>
  )
}
```

---

### Combobox (Popover + Command)

The other major cmdk usage — a searchable single-select combobox built from Command inside a [Popover](/components/popover).

**Install:**

```bash
npx shadcn@latest add @designrevision/command-combobox-01
```

**Dependencies:** lucide-react, command, popover, button

```tsx
// components/ui/command-combobox-01.tsx
"use client"

import * as React from "react"
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"

const frameworks = [
  { value: "next.js", label: "Next.js" },
  { value: "sveltekit", label: "SvelteKit" },
  { value: "nuxt.js", label: "Nuxt.js" },
  { value: "remix", label: "Remix" },
  { value: "astro", label: "Astro" },
]

export default function CommandCombobox01() {
  const [open, setOpen] = React.useState(false)
  const [value, setValue] = React.useState("")

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          variant="outline"
          role="combobox"
          aria-expanded={open}
          className="w-[200px] justify-between"
        >
          {value
            ? frameworks.find((f) => f.value === value)?.label
            : "Select framework…"}
          <ChevronsUpDownIcon className="opacity-50" />
        </Button>
      </PopoverTrigger>
      <PopoverContent className="w-[200px] p-0">
        <Command>
          <CommandInput placeholder="Search framework…" />
          <CommandList>
            <CommandEmpty>No framework found.</CommandEmpty>
            <CommandGroup>
              {frameworks.map((framework) => (
                <CommandItem
                  key={framework.value}
                  value={framework.value}
                  onSelect={(currentValue) => {
                    setValue(currentValue === value ? "" : currentValue)
                    setOpen(false)
                  }}
                >
                  <CheckIcon
                    className={cn(
                      "mr-2",
                      value === framework.value ? "opacity-100" : "opacity-0"
                    )}
                  />
                  {framework.label}
                </CommandItem>
              ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}
```

---

### Disabled & empty

Dimmed, unselectable items via the `disabled` prop, plus the `CommandEmpty` no-results message.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-disabled-01
```

**Dependencies:** command

```tsx
// components/ui/command-disabled-01.tsx
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandShortcut,
} from "@/components/ui/command"

export default function CommandDisabled01() {
  return (
    <Command className="rounded-lg border shadow-md md:min-w-[450px]">
      <CommandInput placeholder="Type a term with no match to see the empty state…" />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Actions">
          <CommandItem>
            New file
            <CommandShortcut>⌘N</CommandShortcut>
          </CommandItem>
          <CommandItem disabled>
            Save (no changes)
            <CommandShortcut>⌘S</CommandShortcut>
          </CommandItem>
          <CommandItem>
            Duplicate
            <CommandShortcut>⌘D</CommandShortcut>
          </CommandItem>
          <CommandItem disabled>Delete (locked)</CommandItem>
        </CommandGroup>
      </CommandList>
    </Command>
  )
}
```

---

### Keyboard footer

An app-grade palette with a sticky footer of [Kbd](/components/kbd) hints — ↵ to select, arrows to navigate, esc to close.

**Install:**

```bash
npx shadcn@latest add @designrevision/command-footer-01
```

**Dependencies:** lucide-react, command, kbd

```tsx
// components/ui/command-footer-01.tsx
import { CornerDownLeftIcon } from "lucide-react"

import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"
import { Kbd } from "@/components/ui/kbd"

export default function CommandFooter01() {
  return (
    <Command className="rounded-lg border shadow-md md:min-w-[450px]">
      <CommandInput placeholder="Type a command or search…" />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Pages">
          <CommandItem>Dashboard</CommandItem>
          <CommandItem>Projects</CommandItem>
          <CommandItem>Team members</CommandItem>
          <CommandItem>Settings</CommandItem>
        </CommandGroup>
      </CommandList>
      <div className="flex items-center justify-between gap-2 border-t px-3 py-2 text-xs text-muted-foreground">
        <div className="flex items-center gap-1">
          <Kbd>
            <CornerDownLeftIcon className="size-3" />
          </Kbd>
          <span>to select</span>
        </div>
        <div className="flex items-center gap-1">
          <Kbd>↑</Kbd>
          <Kbd>↓</Kbd>
          <span>to navigate</span>
          <span className="mx-1">·</span>
          <Kbd>esc</Kbd>
          <span>to close</span>
        </div>
      </div>
    </Command>
  )
}
```
