# Command

A command palette and searchable list built on cmdk, with filtering, groups, keyboard navigation, shortcuts, and an optional dialog wrapper.

- Category: Overlays & Navigation
- License: MIT
- Page: https://www.saasuji.com/components/command
- Install: npx shadcn@latest add https://www.saasuji.com/r/command.json

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| shouldFilter (Command) | `boolean` | `true` | Turns off cmdk automatic filtering when false so items can be filtered manually. |
| filter (Command) | `CommandFilter` | — | Custom scoring function returning a 0–1 score for each item against the search query. |
| value (Command) | `string` | — | Controlled value of the currently selected item. |
| defaultValue (Command) | `string` | — | Initially selected item value for an uncontrolled command. |
| onValueChange (Command) | `(value: string) => void` | — | Called when the selected item changes. |
| loop (Command) | `boolean` | `false` | Wraps arrow-key navigation from the last item back to the first. |
| disablePointerSelection (Command) | `boolean` | `false` | Disables selecting items with the pointer, leaving keyboard selection only. |
| vimBindings (Command) | `boolean` | `true` | Enables the ctrl+n/j/p/k keyboard shortcuts. |
| label (Command) | `string` | — | Accessible label for the command menu, announced but not shown. |
| title (CommandDialog) | `string` | `"Command Palette"` | Screen-reader-only dialog title. |
| description (CommandDialog) | `string` | `"Search for a command to run..."` | Screen-reader-only dialog description. |
| showCloseButton (CommandDialog) | `boolean` | `false` | Shows the corner close button inside the dialog content. |
| placeholder (CommandInput) | `string` | — | Hint text shown while the search query is empty. |
| value (CommandInput) | `string` | — | Controlled search query. |
| defaultValue (CommandInput) | `string` | — | Initial search query for an uncontrolled input. |
| onValueChange (CommandInput) | `(search: string) => void` | — | Called on every keystroke with the current search string. |
| disabled (CommandInput, CommandItem) | `boolean` | `false` | Disables the search input or an individual item. |
| value (CommandItem) | `string` | — | Unique item value; required when the item text content changes between renders. |
| onSelect (CommandItem) | `(value: string) => void` | — | Called when the item is chosen by click or keyboard selection. |
| keywords (CommandItem) | `string[]` | — | Extra terms matched while filtering the item. |
| forceMount (CommandItem, CommandGroup, CommandEmpty) | `boolean` | — | Renders the part regardless of the active filter. |
| heading (CommandGroup) | `React.ReactNode` | — | Group label rendered above the grouped items. |
| alwaysRender (CommandSeparator) | `boolean` | `false` | Keeps the separator visible while a search query is active. |
| className (all parts) | `string` | — | Additional classes merged onto the part that receives it. |
| children (all parts) | `React.ReactNode` | — | Search input, list, groups, items, and shortcuts; CommandDialog wraps the same tree in a Dialog. |
| ...props (Command) | `React.ComponentProps<typeof CommandPrimitive>` | — | All remaining cmdk Command props and native div attributes are forwarded. |
| ...props (CommandDialog) | `React.ComponentProps<typeof Dialog>` | — | All remaining Dialog props are forwarded (open, defaultOpen, onOpenChange, …). |
| ...props (CommandInput, CommandList, CommandEmpty, CommandGroup, CommandSeparator, CommandItem) | `React.ComponentProps<typeof CommandPrimitive.Input> | React.ComponentProps<typeof CommandPrimitive.List> | React.ComponentProps<typeof CommandPrimitive.Empty> | React.ComponentProps<typeof CommandPrimitive.Group> | React.ComponentProps<typeof CommandPrimitive.Separator> | React.ComponentProps<typeof CommandPrimitive.Item>` | — | All remaining cmdk props are forwarded to the part that receives them. |
| ...props (CommandShortcut) | `React.ComponentProps<"span">` | — | All remaining span attributes are forwarded to the shortcut hint. |

## Source

```tsx
"use client"

import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
import Search from "lucide-react/dist/esm/icons/search"

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(
        "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
        className
      )}
      {...props}
    />
  )
}

function CommandDialog({
  title = "Command Palette",
  description = "Search for a command to run...",
  children,
  className,
  showCloseButton = false,
  ...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]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:size-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:size-5">
          {children}
        </Command>
      </DialogContent>
    </Dialog>
  )
}

function CommandInput({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
  return (
    <div
      data-slot="command-input-wrapper"
      className="flex h-12 items-center gap-2.5 border-b px-3.5"
    >
      <Search className="size-4 shrink-0 opacity-50" />
      <CommandPrimitive.Input
        data-slot="command-input"
        className={cn(
          "flex h-11 w-full bg-transparent py-3 text-sm outline-none focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 border-none shadow-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        style={{ outline: "none", boxShadow: "none", border: "none" }}
        {...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(
        "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[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-1 h-px bg-border", className)}
      {...props}
    />
  )
}

function CommandItem({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
  return (
    <CommandPrimitive.Item
      data-slot="command-item"
      className={cn(
        "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 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground",
        className
      )}
      {...props}
    />
  )
}

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

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

```
