Command Palette

A ⌘K command palette with fuzzy search and keyboard navigation, reusing the modal behavior primitive — zero extra runtime.

Real use · ⌘K launcher (try the hotkey too)

Using Command Palette

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Command Palette is styled but inert: its behavior comes from modal. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class command-palette-backdrop, with 14 modifiers:

  • .command-palette-backdrop
  • .command-palette-empty
  • .command-palette-group
  • .command-palette-group-label
  • .command-palette-input
  • .command-palette-item
  • .command-palette-item-body
  • .command-palette-item-desc
  • .command-palette-item-icon
  • .command-palette-item-label
  • .command-palette-item-shortcut
  • .command-palette-list
  • .command-palette-popup
  • .command-palette-search
  • .command-palette-search-icon

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { CommandPalette } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
itemsCommandItem[]yesThe commands to show and filter.
openbooleannoControlled open state.
defaultOpenbooleannoUncontrolled initial open state.
onOpenChange(open: boolean) => voidno—
placeholderstringnoSearch box placeholder.
emptyMessagestringnoShown when nothing matches.
hotkeyboolean | stringnoGlobal toggle hotkey. true (default) binds ⌘K / Ctrl+K; pass a single letter to rebind (still combined with ⌘/Ctrl); false disables it.
classNamestringno—

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { useState } from "react";
import { CommandPalette, Button } from "@wizeworks/silicaui-react";
import type { CommandItem } from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";

export function CommandPaletteDemo() {
    const [open, setOpen] = useState(false);
    const [lastCommand, setLastCommand] = useState<string | null>(null);

    const items: CommandItem[] = [
        {
            id: "new-page",
            label: "Create new page",
            description: "Add a blank page to this site",
            group: "Actions",
            shortcut: "⌘N",
            onSelect: () => setLastCommand("Create new page"),
        },
        {
            id: "invite",
            label: "Invite teammate",
            group: "Actions",
            keywords: ["member", "user", "collaborator"],
            onSelect: () => setLastCommand("Invite teammate"),
        },
        {
            id: "theme-light",
            label: "Switch to light theme",
            group: "Preferences",
            onSelect: () => setLastCommand("Switch to light theme"),
        },
        {
            id: "theme-dark",
            label: "Switch to dark theme",
            group: "Preferences",
            onSelect: () => setLastCommand("Switch to dark theme"),
        },
        {
            id: "billing",
            label: "Open billing settings",
            group: "Preferences",
            disabled: true,
            onSelect: () => setLastCommand("Open billing settings"),
        },
    ];

    return (
        <Section title="Real use · ⌘K launcher (try the hotkey too)">
            <Row>
                <Button color="primary" onClick={() => setOpen(true)}>
                    Open command palette
                </Button>
                {lastCommand && (
                    <span className="text-sm opacity-70">Ran: {lastCommand}</span>
                )}
            </Row>
            <CommandPalette items={items} open={open} onOpenChange={setOpen} />
        </Section>
    );
}

Vanilla — node tree to HTML

CommandPalette — params.hotkey binds ⌘K/Ctrl+K globally (default true; props.hotkey === false disables it). Input/Item reuse the search/item parts modal.ts optionally wires filter+arrow-nav for. Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("CommandPalette", "command-palette-backdrop", { /* props */ }, [/* children */]);
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "command-palette-backdrop command-palette-backdrop-primary" rather than passing a colour as a prop.

Takes children
yes
Hydrated by
modal

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Command Palette, on every path, is available through the Silica MCP server.