plugins

CommandPalette

Cmd+K-style fuzzy-search launcher.


@plyxui/plugins/command-palette exports CommandPalette — a keyboard-driven launcher you can wire to any action set.

Try it live

import { useEffect, useState } from "react";
import { CommandPalette } from "@plyxui/plugins";
import { Box, Button, Text } from "@plyxui/primitives";

export default function App() {
const [open, setOpen] = useState(false);
const [last, setLast] = useState("");
useEffect(() => {
  const onKey = (e) => {
    if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); setOpen((v) => !v); }
  };
  window.addEventListener("keydown", onKey);
  return () => window.removeEventListener("keydown", onKey);
}, []);
const items = [
  { id: "new-doc",   label: "New document",   onSelect: () => setLast("New document") },
  { id: "open",      label: "Open file…",     onSelect: () => setLast("Open file") },
  { id: "settings",  label: "Settings",       onSelect: () => setLast("Settings") },
  { id: "logout",    label: "Sign out",       onSelect: () => setLast("Sign out") },
];
return (
  <Box padding="lg" style={{ minHeight: "100vh" }}>
    <Button onClick={() => setOpen(true)}>Open palette (or press ⌘K)</Button>
    <Text size="sm" style={{ marginTop: 12, opacity: 0.7 }}>Last action: {last || "(none yet)"}</Text>
    <CommandPalette open={open} onClose={() => setOpen(false)} items={items} placeholder="Search commands…" />
  </Box>
);
}

Install

npm install @plyxui/plugins

Usage

import { CommandPalette } from "@plyxui/plugins";
import { useDisclosure } from "@plyxui/hooks";

function App() {
  const { isOpen, open, close } = useDisclosure();

  // Wire your trigger -- Cmd+K is the obvious choice
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        open();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open]);

  return (
    <>
      <YourApp />
      <CommandPalette
        open={isOpen}
        onClose={close}
        items={[
          { id: "home",     label: "Go home",      group: "Navigate", icon: "home",     onSelect: () => navigate("/") },
          { id: "settings", label: "Open settings", group: "Navigate", icon: "settings", onSelect: () => navigate("/settings") },
          { id: "logout",   label: "Sign out",     group: "Account",  onSelect: signOut },
        ]}
      />
    </>
  );
}

Item shape

FieldRequiredWhat
idyesStable identifier (used as React key).
labelyesWhat the user sees in the list.
onSelectyesCalled when the user picks this item. The palette closes after.
groupnoLogical group header (e.g. "Navigate", "Account"). Ungrouped items appear at top.
iconnoIcon name from the @plyxui/icons registry.
keywordsnoExtra strings included in substring matching. Useful for aliases ("logout", "signout", "log out").
disablednoGreys out the item; Enter / click are ignored.

Matching

Items are ranked by:

  • Prefix match on label or any keyword: highest.
  • Substring match on label or any keyword: middle.
  • No match: filtered out.

This is deliberately simple. Sub-200-item lists feel snappy. If you have thousands of items and need fzf-style fuzzy matching, file an issue.

Keyboard

KeyAction
/ Move selection
EnterRun the selected item
EscClose the palette
Click outsideClose the palette