Command Menu

A mobile-friendly command palette for search and quick actions.

Built with:

Installation

pnpm dlx shadcn@latest add @lumi-ui/command-menu

Anatomy

<CommandMenu>
  <CommandMenuTrigger />
  <CommandMenuContent>
    <Command items={groupedItems}>
      <CommandInput />
      <CommandEmpty />
      <CommandScrollArea>
        <CommandList>
          <CommandGroup>
            <CommandGroupLabel />
            <CommandCollection>
              <CommandItem>
                <CommandShortcut />
              </CommandItem>
            </CommandCollection>
          </CommandGroup>
          <CommandSeparator />
        </CommandList>
      </CommandScrollArea>
    </Command>
    <CommandMenuFooter />
  </CommandMenuContent>
</CommandMenu>

Basic Usage

"use client";
 
import * as React from "react";
import {
  Command,
  CommandCollection,
  CommandEmpty,
  CommandGroup,
  CommandGroupLabel,
  CommandInput,
  CommandItem,
  CommandList,
  CommandMenu,
  CommandMenuContent,
  CommandMenuTrigger,
  CommandScrollArea,
} from "@/components/ui/command-menu";
import { Button } from "@/components/ui/button";
 
export function CommandMenuMinimal() {
  const [open, setOpen] = React.useState(false);
 
  return (
    <CommandMenu onOpenChange={setOpen} open={open}>
      <CommandMenuTrigger render={<Button variant="outline">Open</Button>} />
      <CommandMenuContent aria-label="Command menu">
        <Command items={groupedItems}>
          <CommandInput placeholder="Search..." />
          <CommandEmpty>No results found.</CommandEmpty>
          <CommandScrollArea>
            <CommandList>
              {(group: Group) => (
                <CommandGroup items={group.items} key={group.value}>
                  <CommandGroupLabel>{group.value}</CommandGroupLabel>
                  <CommandCollection>
                    {(item: Item) => (
                      <CommandItem
                        key={item.value}
                        onClick={() => setOpen(false)}
                        value={item}
                      >
                        {item.label}
                      </CommandItem>
                    )}
                  </CommandCollection>
                </CommandGroup>
              )}
            </CommandList>
          </CommandScrollArea>
        </Command>
      </CommandMenuContent>
    </CommandMenu>
  );
}
 
type Item = { value: string; label: string };
type Group = { value: string; items: Item[] };
 
const groupedItems: Group[] = [
  {
    value: "Resources",
    items: [
      { label: "Documentation", value: "docs" },
      { label: "Components", value: "components" },
    ],
  },
  {
    value: "Actions",
    items: [{ label: "Settings", value: "settings" }],
  },
];

Cookbook

These customizations are done in components/ui/command-menu.tsx.

Center command menu

<DialogViewport
  className={cn(
    "flex flex-col items-center justify-center",
    // add top padding to move the popup down
     "pt-[10dvh]",
  )}
>

Adjust position

Use viewport top padding to place the popup higher or lower:

  • pt-[20dvh]: lower
  • pt-[10dvh]: default
  • pt-[5dvh]: higher
<DialogViewport className={cn("flex flex-col items-center", "pt-[10dvh]")} />

Tune popup width and animation

In CommandMenuContent, this class controls width and default animation:

"w-[min(40rem,calc(100vw-2rem))] animate-fade-zoom"
  • w-[min(40rem,calc(100vw-2rem))] keeps the menu mobile-friendly.
  • Swap animate-fade-zoom for any supported utility from Animation Guide.

CommandScrollArea

Default CommandScrollArea uses:

"h-auto max-h-64 sm:max-h-96"
  • h-auto keeps content height fluid.
  • max-h-64 is optional and makes the list shorter.

You can skip CommandScrollArea and use your own container:

<div className="h-auto max-h-80 overflow-y-auto">
  <CommandList>{/* items */}</CommandList>
</div>

Swap Input

CommandInput is built on AutocompleteInputGroup and can show a clear button (showClear).

If you need full control, replace it with AutocompleteInput:

import { AutocompleteInput } from "@/components/ui/autocomplete";
 
<Command items={groupedItems}>
  <AutocompleteInput className="border-b px-4 py-3" placeholder="Search..." />
</Command>

Tune CommandItem highlight

CommandItem uses highlighted inset classes:

"group/command-item ... data-[highlighted]:before:inset-x-3"

Adjust the inset value (inset-x-2, inset-x-4, etc.) to change the pill width without adding padding on the parent list container.

See Hit-Test & Highlights for the pattern details.

API Reference

CommandMenuContent

A composite content wrapper that combines DialogPortal, DialogBackdrop, DialogViewport, and DialogPopup.

PropTypeDescription
classNamestringAdditional CSS classes for the popup container.
childrenReact.ReactNodeContent rendered inside the popup.
...propsDialogPopupPropsPasses all other props to the underlying dialog popup.

Command

A preconfigured autocomplete root for command interactions.

PropTypeDescription
autoHighlightAutocomplete propDefaults to "always" for keyboard-first flows.
inlinebooleanDefaults to true to keep list rendering inline.
keepHighlightbooleanDefaults to true to preserve highlighted item state.
openbooleanDefaults to true so list remains visible in the dialog.
...propsReact.ComponentProps<typeof Autocomplete>Passes all other props to the underlying autocomplete root.

CommandInput

A composite input based on AutocompleteInputGroup.

PropTypeDescription
addonIconReact.ReactNodePrefix icon; defaults to <Search />.
inputSize"default" | "sm" | "lg"Input size; defaults to "lg".
classNamestringAdditional classes for the input group.
...propsReact.ComponentProps<typeof AutocompleteInputGroup>Passes all other input-group props.

CommandScrollArea

Scroll container for command results.

PropTypeDescription
classNamestringAdditional CSS classes.
...propsReact.ComponentProps<typeof ScrollArea>Passes all other props to the underlying scroll area.

CommandItem

Styled command row with built-in highlight states.

PropTypeDescription
classNamestringAdditional classes for item layout and interaction styling.
...propsAutocompleteItemPropsPasses all other props to the underlying autocomplete item.