Skip to content
shadcn.io
shadcn.io is not affiliated with official shadcn/ui

Shadcn Command for React and Tailwind

Searchable command input with filtering.

Linear⌘L
Figma⌘F
Slack⌘S
YouTube⌘Y
Raycast⌘R
Settings⌘,
Help⌘?
About⌘I
Feedback⌘B
Support⌘P
Updates⌘U
Logout⌘Q
Sign out⌘O
Sign in⌘A

Installation

bunx --bun shadcn@latest add https://kit.dev/r/command.json

Anatomy

Command
├── CommandInput
│   ├── ComboboxControl (built in)
│   └── search icon (built in)
├── CommandContent
│   ├── CommandEmpty
│   └── CommandList
│       └── CommandGroup
│           ├── CommandGroupLabel
│           └── CommandItem
│               └── CommandShortcut (optional)
├── CommandSeparator
└── CommandFooter (optional)

CommandDialog
├── CommandDialogTrigger
└── CommandDialogContent
    └── Command

Command is Combobox with palette defaults: the list stays open, selection clears the input, and the first match is highlighted while typing. CommandContent is inline (not portaled). useCommand is the machine hook for CommandRootProvider; useCommandContext / CommandContext is in-tree.

CommandDialog is Dialog. CommandDialogContent portals overlay + positioner, hides the title and description visually (sr-only), and does not render a close button.

Usage

import { useListCollection } from "@ark-ui/react/collection";
import { useFilter } from "@ark-ui/react/locale";
import {
  Command,
  CommandContent,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command";
const { contains } = useFilter({ sensitivity: "base" });
const { collection, filter } = useListCollection({
  initialItems: [
    { label: "Search", value: "search", group: "Actions" },
    { label: "Settings", value: "settings", group: "Actions" },
  ],
  filter: contains,
  groupBy: (item) => item.group,
});

<Command
  collection={collection}
  onInputValueChange={({ inputValue }) => filter(inputValue)}
>
  <CommandInput placeholder="Search..." />
  <CommandContent>
    <CommandEmpty />
    <CommandList>
      {collection.group().map(([group, items]) => (
        <CommandGroup heading={group} key={group}>
          {items.map((item) => (
            <CommandItem item={item} key={item.value}>
              {item.label}
            </CommandItem>
          ))}
        </CommandGroup>
      ))}
    </CommandList>
  </CommandContent>
</Command>

shadcn.io Command defaults (vs Combobox / Ark): open true, closeOnSelect false, disableLayer true, inputBehavior "autohighlight", loopFocus false, selectionBehavior "clear", lazyMount / unmountOnExit true. Selected values are always a string[].

Controlled

Control the last selected command with value and onValueChange. Selected values are always a string[]. selectionBehavior="clear" still clears the input after select.

Root Provider

Use useCommand with CommandRootProvider when you need the API outside the tree. useCommand() applies the same palette defaults as Command. Pass collection and handlers to useCommand(), not to the provider.

Examples

With Dialog

Wrap Command in CommandDialog. Close the dialog from onValueChange after a command is chosen.

Groups

Group related items with groupBy on the collection and collection.group() when rendering. CommandGroup accepts a heading for the label. Put CommandSeparator between groups as a sibling (give the wrapping fragment a key).

Shortcuts

Display keyboard shortcuts next to items with CommandShortcut.

Add hints or actions in CommandFooter. Place it after CommandContent so the list can round and border correctly.

Scrollable

CommandList caps height at max-h-72. Long collections scroll inside the list.

Context

Read highlighted and selected state with CommandContext or useCommandContext.

Guides

Command vs Combobox

CommandComboboxAutocomplete
PurposeRun an actionPick from a known setFree text with suggestions
ListAlways openPopoverPopover
Input behaviorautohighlightnoneautocomplete
After selectClears inputReplaces inputReplaces input
TriggerNone (search field)ChevronHidden

Use Menu for a short action list without search. Use Select when there is no search and the value stays on the control.

Dialog palettes

Keep CommandDialog mounted and control it with open / onOpenChange. Close it from onValueChange when a command should run and dismiss:

<CommandDialog onOpenChange={(e) => setOpen(e.open)} open={open}>
  <CommandDialogTrigger asChild>
    <Button>Open</Button>
  </CommandDialogTrigger>
  <CommandDialogContent>
    <Command
      collection={collection}
      onInputValueChange={({ inputValue }) => filter(inputValue)}
      onValueChange={() => setOpen(false)}
    >

CommandDialogContent sets a visually hidden title (Command Palette) and description. Override with title and description.

Collections

Items live in an Ark collection, not a loose items prop on the root.

const { contains } = useFilter({ sensitivity: "base" });
const { collection, filter } = useListCollection({
  initialItems,
  filter: contains,
});

<Command
  collection={collection}
  onInputValueChange={({ inputValue }) => filter(inputValue)}
>

Call filter(inputValue) from onInputValueChange. Render collection.items (or collection.group() when grouping).

Keys in grouped lists

When a separator sits beside a group, wrap both in a fragment and put key on the fragment — not only on CommandGroup:

{collection.group().map(([group, items], index) => (
  <Fragment key={group}>
    {index !== 0 && <CommandSeparator />}
    <CommandGroup heading={group}>
      {items.map((item) => (
        <CommandItem item={item} key={item.value}>
          {item.label}
        </CommandItem>
      ))}
    </CommandGroup>
  </Fragment>
))}

API Reference

shadcn.io Command wraps Combobox (Ark Combobox machine). Defaults below are shadcn.io Command values. data-scope stays combobox; shadcn.io sets data-slot="command" on the root.

asChild merges props onto a single child element.

Command

Root. Renders a div. Requires a collection. The list is open by default.

PropTypeDefaultDescription
collectionListCollection<T>requiredItems to show. Create with useListCollection or createListCollection.
allowCustomValuebooleanfalseAllow values that are not in the collection.
alwaysSubmitOnEnterbooleanfalseSubmit on Enter even if the list is open.
asChildbooleanfalseRender the child element instead of a div.
autoFocusboolean-Focus the input on mount. Prefer autoFocus on CommandInput (already true there).
classNamestring-Class names on the root.
closeOnSelectbooleanfalseClose the list when an item is selected. Command keeps the list open.
compositebooleantrueTreat as composed with other composite widgets such as tabs.
defaultHighlightedValuestring | null-Uncontrolled initial highlighted value.
defaultInputValuestring""Uncontrolled initial input text.
defaultOpenboolean-Uncontrolled initial open state. Command sets open to true.
defaultValuestring[][]Uncontrolled selected values.
disabledboolean-Disable the command.
disableLayerbooleantrueDo not register as a dismissable layer. The dialog is the layer when used in CommandDialog.
formstring-Associated form id.
hideMode"display-none" | "activity""display-none"How to hide mounted-but-closed content. activity needs React 19+.
highlightedValuestring | null-Controlled highlighted value.
idstring-Unique id for the machine.
idsPartial<{ root: string; label: string; control: string; input: string; content: string; trigger: string; clearTrigger: string; item: (id: string, index?: number) => string; positioner: string; itemGroup: (id: string | number) => string; itemGroupLabel: (id: string | number) => string }>-Element ids for composition.
immediateboolean-Apply presence changes immediately instead of the next frame.
inputBehavior"none" | "autocomplete" | "autohighlight""autohighlight"Highlights the first match while typing.
inputValuestring-Controlled input text.
invalidboolean-Mark as invalid.
lazyMountbooleantrueMount content on first open.
loopFocusbooleanfalseDo not loop keyboard focus through items.
multipleboolean-Allow more than one selected value.
namestring-name on the input for form submission.
navigate(details: NavigateDetails) => void-Called when a link item is chosen. { value, node, href }.
onExitComplete() => void-Called when the close animation finishes.
onFocusOutside(event: FocusOutsideEvent) => void-Called when focus moves outside.
onHighlightChange(details: HighlightChangeDetails<T>) => void-Called when the highlighted item changes. { highlightedValue, highlightedItem }.
onInputValueChange(details: InputValueChangeDetails) => void-Called when the input text changes. { inputValue, reason }. Filter the collection here.
onInteractOutside(event: InteractOutsideEvent) => void-Called on outside interaction.
onOpenChange(details: OpenChangeDetails) => void-Called when open state changes. { open, reason, value }.
onPointerDownOutside(event: PointerDownOutsideEvent) => void-Called on pointer down outside.
onSelect(details: SelectionDetails) => void-Called when an item is selected. { value, itemValue }.
onValueChange(details: ValueChangeDetails<T>) => void-Called when the selection changes. { value: string[]; items: T[] }. Close a dialog from here.
openbooleantrueControlled open state. Command keeps the list open unless you override this.
openOnChangeboolean | ((details: InputValueChangeDetails) => boolean)trueOpen the list when the input value changes.
openOnClickbooleantrueOpen the list on click in the input.
openOnKeyPressbooleantrueOpen the list on arrow keys.
placeholderstring-Placeholder on the root. Prefer placeholder on CommandInput.
positioningPositioningOptions{ placement: "bottom-start" }Floating position. Unused while CommandContent is inline.
presentboolean-Controlled presence.
readOnlyboolean-Non-editable, but still interactive.
requiredboolean-Mark as required.
scrollToIndexFn(details: ScrollToIndexDetails) => void-Scroll a virtualized list to an index. { index, immediate, getElement }.
selectionBehavior"clear" | "replace" | "preserve""clear"After select, clear the input.
skipAnimationOnMountbooleanfalseSkip the initial presence animation.
translationsIntlTranslations-{ triggerLabel?, clearTriggerLabel? } for assistive labels.
unmountOnExitbooleantrueUnmount after the close animation.
valuestring[]-Controlled selected values.
AttributeDescription
data-slotcommand
data-scopecombobox
data-partroot
data-invalidPresent when invalid
data-readonlyPresent when read-only

CommandDialog

Dialog root for a palette overlay. Same API as Dialog (open, onOpenChange, lazyMount, modal, …). shadcn.io defaults lazyMount and unmountOnExit to true.

PropTypeDefaultDescription
openboolean-Controlled open state.
defaultOpenbooleanfalseUncontrolled initial open state.
onOpenChange(details: { open: boolean }) => void-Called when the dialog opens or closes.
modalbooleantrueTrap pointer events and hide content behind the dialog.
lazyMountbooleantrueMount content on first open.
unmountOnExitbooleantrueUnmount content after the close animation.

See Dialog for the full root API.

CommandDialogTrigger

Opens the palette. Same as DialogTrigger. Renders a button.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child (for example Button).
classNamestring-Class names on the trigger.
AttributeDescription
data-slotcommand-dialog-trigger
data-scopedialog
data-parttrigger
data-state"open" or "closed"

CommandDialogContent

Portaled dialog panel. Includes overlay and positioner. Renders a visually hidden DialogHeader (title + description). No close button — dismiss with Escape, outside click, or onValueChange.

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "fullscreen""lg"Max width of the panel. lg is max-w-xl.
titlestring"Command Palette"Accessible dialog title (visually hidden).
descriptionstring"Search for a command to run..."Accessible dialog description (visually hidden).
bottomStickOnMobileboolean-Stick the panel to the bottom of the viewport below sm.
positionerClassNamestring-Class names on the viewport-fixed positioner.
classNamestring-Class names on the panel. Padding and border are removed (p-0 border-0).
asChildbooleanfalseMerge onto a single child of the panel.

showCloseButton is accepted (from DialogContent) but ignored.

AttributeDescription
data-slotcommand-dialog-content
data-scopedialog
data-partcontent
data-state"open" or "closed"

CommandInput

Search field with a decorative search icon. Uses Input Group. autoFocus is on by default. aria-label falls back to placeholder, then "Search".

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Control height. sm is h-7, md is h-8, lg is h-9.
placeholderstring-Placeholder on the input. Also used as aria-label when none is set.
disabledboolean-Disable the input.
classNamestring-Class names on the input group.
asChildbooleanfalseMerge onto the underlying input.

Native input attributes pass through to the input.

AttributeDescription
data-slotcommand-input on the input
data-scopecombobox
data-partinput
data-invalidPresent when invalid
data-state"open" or "closed"

The control wrapper keeps Combobox slots (combobox-control).

CommandContent

Inline list surface (not portaled). Renders a div. Sits under the input; pair with CommandFooter after it in the tree.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the content.
AttributeDescription
data-slotcommand-content
data-scopecombobox
data-partcontent
data-state"open" or "closed"
data-emptyPresent when there are no items
CSS variableDescription
--available-heightUsed as max-h-(--available-height)
--layer-indexIndex in the dismissable layer stack
--nested-layer-countNumber of nested comboboxes

CommandList

Wraps the options. Outer wrapper is max-h-72. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the list.
AttributeDescription
data-slotcommand-list
data-scopecombobox
data-partlist
data-emptyPresent when there are no items

CommandEmpty

Shown when the filtered collection has no items. Default children: No results found.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the empty state.
childrenReactNodeNo results found.Empty message.
AttributeDescription
data-slotcommand-empty
data-scopecombobox
data-partempty

CommandGroup

Groups related options. Pass heading to render CommandGroupLabel.

PropTypeDefaultDescription
headingstring | ReactNode-Group label.
idstring-Group id.
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the group.
AttributeDescription
data-slotcommand-group
data-scopecombobox
data-partitem-group
data-emptyPresent when the group is empty

CommandGroupLabel

Label for a group. Usually created by heading on CommandGroup. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the label.
AttributeDescription
data-slotcommand-group-label
data-scopecombobox
data-partitem-group-label

CommandItem

A single command. Always uses persistFocus. No check indicator (unlike Combobox). Renders a div.

PropTypeDefaultDescription
itemTrequiredCollection item.
asChildbooleanfalseMerge onto a single child (for example an <a>).
classNamestring-Class names on the item.
persistFocusbooleantrueKeep highlight when the pointer leaves.
AttributeDescription
data-slotcommand-item
data-scopecombobox
data-partitem
data-highlightedPresent when highlighted
data-state"checked" or "unchecked"
data-disabledPresent when disabled
data-valueThe item value

CommandSeparator

Separator between groups or items.

PropTypeDefaultDescription
classNamestring-Class names on the separator.
AttributeDescription
data-slotcommand-separator

CommandShortcut

Keyboard shortcut hint. Renders a span aligned to the end of the item (Menu shortcut styles).

PropTypeDefaultDescription
classNamestring-Class names on the shortcut.
asChildbooleanfalseMerge onto a single child.
AttributeDescription
data-slotcommand-shortcut

CommandFooter

Footer for hints or extra actions. Place after CommandContent. Renders a div.

PropTypeDefaultDescription
classNamestring-Class names on the footer.
AttributeDescription
data-slotcommand-footer

CommandRootProvider

Root alternative that takes the API from useCommand. Renders a div with the same chrome as Command.

PropTypeDefaultDescription
valueUseComboboxReturn<T>requiredReturn value of useCommand().
asChildbooleanfalseRender the child element instead of a div.
classNamestring-Class names on the root.
hideMode"display-none" | "activity""display-none"How to hide mounted-but-closed content.
immediateboolean-Apply presence changes immediately.
lazyMountbooleantrueMount content on first open.
onExitComplete() => void-Called when the close animation finishes.
presentboolean-Controlled presence.
skipAnimationOnMountbooleanfalseSkip the initial presence animation.
unmountOnExitbooleantrueUnmount after the close animation.

Pass collection and handlers to useCommand(), not to CommandRootProvider.

AttributeDescription
data-slotcommand
data-scopecombobox
data-partroot

useCommand

Creates the command API for CommandRootProvider. Same options as Command, with palette defaults already applied (open, inputBehavior, selectionBehavior, closeOnSelect, disableLayer, loopFocus).

const command = useCommand({
  collection,
  onInputValueChange: (details) => filter(details.inputValue),
});

command.focus();

CommandContext / useCommandContext

Render-prop or hook access to command state. Use inside Command or CommandRootProvider.

PropertyTypeDescription
focusedbooleanWhether the input is focused.
openbooleanWhether the list is open.
inputValuestringCurrent input text.
highlightedValuestring | nullValue of the highlighted item.
highlightedItemT | nullHighlighted item.
setHighlightValue(value: string) => voidHighlight an item by value.
clearHighlightValue() => voidClear the highlight.
syncSelectedItems() => voidSync selected items after an async collection load.
selectedItemsT[]Selected items.
hasSelectedItemsbooleanWhether any item is selected.
valuestring[]Selected values.
valueAsStringstringSelected items as a string.
selectValue(value: string) => voidSelect a value.
setValue(value: string[]) => voidSet the selection.
clearValue(value?: string) => voidClear one value, or all if omitted.
focus() => voidFocus the input.
setInputValue(value: string, reason?: InputValueChangeReason) => voidSet the input text.
getItemState(props: { item: T; persistFocus?: boolean }) => ItemStateState for one item (value, disabled, selected, highlighted).
setOpen(open: boolean, reason?: OpenChangeReason) => voidOpen or close the list.
collectionListCollection<T>Current collection.
reposition(options?: Partial<PositioningOptions>) => voidUpdate list position.
multiplebooleanWhether multiple selection is on.
disabledbooleanWhether the command is disabled.

CommandContext children: (context) => ReactNode.

CommandItemContext / useCommandItemContext

Render-prop or hook access to one item. Use inside CommandItem.

PropertyTypeDescription
valuestringItem value.
disabledbooleanWhether the item is disabled.
selectedbooleanWhether the item is selected.
highlightedbooleanWhether the item is highlighted.

CommandItemContext children: (context) => ReactNode.

Accessibility

Complies with the Combobox WAI-ARIA design pattern. CommandInput labels itself from aria-label, then placeholder, then "Search". Dialog palettes also expose CommandDialogContent title / description to assistive tech (visually hidden). Keep CommandEmpty so a filtered list is not a blank panel.

Keyboard support

KeyDescription
ArrowDownMoves to the next option. Opens the list if it was closed.
ArrowUpMoves to the previous option. Opens the list if it was closed.
HomeMoves to the first option.
EndMoves to the last option.
EnterRuns the highlighted command. Clears the input (selectionBehavior="clear").
EscapeClears highlight / input. In CommandDialog, also closes the dialog.