WebberUI

Command Palette

A ⌘K command palette with live fuzzy search, grouped commands, and keyboard navigation, its highlight row sliding via a shared layout.

Loading preview…
npx shadcn@latest add https://webberui.com/r/command-palette.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

<CommandPalette />

Installation

npx shadcn@latest add https://webberui.com/r/command-palette.json

Or, once registries are configured in components.json, install it as @webberui/command-palette.

Usage

import * as React from "react";
import { Home, Plus } from "lucide-react";
import { CommandPalette } from "@/components/ui/command-palette";

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

  const groups = [
    {
      heading: "Navigation",
      items: [
        {
          id: "home",
          label: "Go to home",
          icon: <Home className="size-4" />,
          shortcut: "G H",
          onSelect: () => console.log("home"),
        },
      ],
    },
    {
      heading: "Actions",
      items: [
        {
          id: "new",
          label: "New document",
          icon: <Plus className="size-4" />,
          shortcut: "⌘ N",
          onSelect: () => console.log("new"),
        },
      ],
    },
  ];

  return <CommandPalette open={open} onOpenChange={setOpen} groups={groups} />;
}

Press ⌘K (macOS) or Ctrl+K (Windows/Linux) to summon the palette at any time; you can also drive it from an external button through open / onOpenChange.

Props

PropTypeDefaultDescription
openbooleanOpen state in controlled mode; when omitted, the component manages it internally
onOpenChange(open: boolean) => voidCallback fired when the open state changes (in both controlled and uncontrolled modes)
groupsCommandPaletteGroup[]Command group data; each group's heading and items are rendered in order
placeholderstring"Type a command or search…"Placeholder text for the search field
classNamestringAppended to the palette container's className

CommandPaletteGroup

FieldTypeDescription
headingstringGroup heading
itemsCommandPaletteItem[]The command items in that group

CommandPaletteItem

FieldTypeDescription
idstringUnique identifier, used as the option's DOM id and the React key
labelstringDisplay text, which is also what search filtering matches against
iconReact.ReactNodeOptional leading icon
shortcutstringOptional keyboard shortcut hint, shown on the right of the item
onSelect() => voidThe action to run when this item is selected (by click or Enter)

How it works

  • A global listener toggles on ⌘K / Ctrl+K; the palette is mounted onto document.body with createPortal.
  • The overlay fades in and the palette scales and fades in, centered slightly above the middle; the search field focuses automatically and typing applies live subsequence fuzzy filtering.
  • The up and down keys cycle the highlight through the filtered items, Enter runs the item, Esc closes, and clicking the overlay closes.
  • The highlight row's background slides smoothly between items via a shared layoutId.

Accessibility

  • The palette is role="dialog" with aria-modal="true"; it locks body scrolling while open and returns focus to the previously focused element after closing.
  • The search field is role="combobox" and points at the currently highlighted item with aria-activedescendant; the results are role="listbox" and the items are role="option" with aria-selected.
  • When the user has "reduce motion" enabled at the system level, the palette only fades in and out by opacity and the highlight row snaps into place, with no scaling or sliding.

On this page