Docs / SDK / Commands & Hotkeys

Commands & Hotkeys

Commands are named actions that can be triggered from the command palette, menu items, toolbar buttons, or keyboard shortcuts. The command system connects them all through a single dispatcher.

Defining commands

Commands are defined as part of a module's ModuleDef. Each command has an ID, label, optional icon, shortcut display, and category for grouping in the palette:

const commands = [
  {
    id: "crm.new-contact",
    label: "New Contact",
    icon: "user-plus",
    shortcut: "Cmd+N",
    category: "CRM",
  },
  {
    id: "crm.search-contacts",
    label: "Search Contacts",
    icon: "search",
    shortcut: "Cmd+F",
    category: "CRM",
  },
  {
    id: "crm.import-csv",
    label: "Import from CSV",
    icon: "upload",
    category: "CRM",
  },
];

Command dispatcher

The CommandDispatcherProvider manages command registration and execution. Wrap your app with it and register handlers for each command:

import { CommandDispatcherProvider, useCommandDispatcher } from "@substrateui/ui/commands";

// In your app root
<CommandDispatcherProvider commands={allCommands}>
  <App />
</CommandDispatcherProvider>

// In any component, register handlers and execute commands
function ContactsPage() {
  const { registerHandler, execute } = useCommandDispatcher();

  useEffect(() => {
    registerHandler("crm.new-contact", async () => {
      setCreateDialogOpen(true);
    });

    registerHandler("crm.search-contacts", async () => {
      searchInputRef.current?.focus();
    });

    return () => {
      unregisterHandler("crm.new-contact");
      unregisterHandler("crm.search-contacts");
    };
  }, []);

  return (
    <button onClick={() => execute("crm.new-contact")}>
      New Contact
    </button>
  );
}

useCommandDispatcher

The hook returns the full dispatcher API:

MethodDescription
registerHandler(id, handler)Register a handler function for a command ID
unregisterHandler(id)Remove a handler for a command ID
execute(id, args?)Execute a command by ID with optional arguments
getCommands()Get all registered command definitions
getRecent()Get recently executed command IDs
search(query)Search commands by label or category

Command palette

The command palette is a searchable overlay (Cmd+K) that lists all available commands grouped by category. It reads from the dispatcher and executes commands on selection:

import { CommandPalette } from "@substrateui/ui/commands";

function App() {
  const [open, setOpen] = useState(false);

  // Cmd+K to open
  useHotkey("mod+k", () => setOpen(true));

  return (
    <CommandPalette
      open={open}
      onOpenChange={setOpen}
      placeholder="Type a command..."
      showShortcuts
      groupByCategory
    />
  );
}

Hotkeys

Hotkeys are keyboard shortcuts defined as part of a module. They map a key combination to a command ID:

// In a module definition
const hotkeys = [
  { id: "crm.new", shortcut: "N", label: "New Contact", commandId: "crm.new-contact" },
  { id: "crm.search", shortcut: "Cmd+F", label: "Search", commandId: "crm.search-contacts" },
  { id: "crm.palette", shortcut: "Cmd+K", label: "Command Palette", commandId: "palette.open" },
];

useHotkeys / useHotkey

Use useHotkeys() to register an array of hotkey definitions with handler functions, or useHotkey() for a single shortcut:

import { useHotkeys, useHotkey } from "@substrateui/ui/commands";

// Register multiple hotkeys from module definitions
useHotkeys(moduleHotkeys, {
  "crm.new": () => setCreateDialogOpen(true),
  "crm.search": () => searchInputRef.current?.focus(),
});

// Register a single shortcut
useHotkey("mod+k", () => setCommandPaletteOpen(true));
useHotkey("Escape", () => setCommandPaletteOpen(false), {
  enabled: commandPaletteOpen,
});

Hotkey options

OptionTypeDescription
enabledbooleanEnable/disable the hotkey (default: true)
scopestringScope name for grouping
activeScopesstring[]Only active when these scopes are active
targetHTMLElement | nullTarget element (default: document)
preventDefaultbooleanPrevent default browser behavior

How it all connects

Commands are the glue between UI surfaces. A single command like crm.new-contact can be triggered from:

  • --Menu bar wsMenuItem with commandId
  • --Toolbar toolBarButton with commandId
  • --Command palette Cmd+K → search → select
  • --Hotkey HotkeyDef with commandId
  • --Code execute("crm.new-contact")

The dispatcher ensures that no matter how the command is triggered, the same handler runs.