Skip to content
Components

Command menu

Offer a searchable set of actions with keyboard navigation.

TS
import { … } from "@fungi.computer/caps/blocks/command-menu";

Commands

TSX
import { CommandMenu } from "@fungi.computer/caps/blocks/command-menu";
import { useState } from "react";
const items = [
{ id: "forage", label: "Start foraging", shortcut: "f" },
{ id: "dry", label: "Dry a batch", shortcut: "d" },
{
id: "label",
label: "Print labels",
description: "Batch 12",
shortcut: "l",
},
];
export default function Commands() {
const [selected, setSelected] = useState("forage");
return (
<CommandMenu
className="w-full max-w-xs"
items={items}
selected={selected}
onSelect={setSelected}
/>
);
}

Disabled

TSX
import { CommandMenu } from "@fungi.computer/caps/blocks/command-menu";
const items = [
{ id: "forage", label: "Start foraging" },
{ id: "dry", label: "Dry a batch" },
{ id: "ship", label: "Ship order", description: "No stock", disabled: true },
];
export default function Disabled() {
return (
<CommandMenu
className="w-full max-w-xs"
items={items}
selected="forage"
onSelect={() => {
/* This specimen has no host action. */
}}
/>
);
}

Interactive

TSX
import { CommandMenu } from "@fungi.computer/caps/blocks/command-menu";
import { useState } from "react";
const items = [
{ id: "forage", label: "Start foraging", shortcut: "f" },
{ id: "dry", label: "Dry a batch", shortcut: "d" },
{ id: "sell", label: "List for sale", shortcut: "s" },
];
export default function Interactive() {
const [selected, setSelected] = useState("forage");
const chosen = items.find((item) => item.id === selected);
return (
<div className="flex flex-col gap-sm">
<CommandMenu
className="w-full max-w-xs"
items={items}
selected={selected}
onSelect={setSelected}
/>
<p className="text-sm">Selected: {chosen?.label}</p>
</div>
);
}

Props

CommandMenuProps

PropTypeDescription
itemsreadonly CommandMenuItem[]
onSelect()(id) => voidCalled after a non-disabled item is selected.
selected?stringCaller-owned selected state; distinct from local keyboard focus.
descriptionPlacement?"end" | "inline"end (default) sets each description at the row's end. inline keeps the label at its own width and starts the description right after it, truncated, so long descriptions never push the row's text apart.
  • itemsreadonly CommandMenuItem[]
  • onSelect()(id) => void

    Called after a non-disabled item is selected.

  • selected?string

    Caller-owned selected state; distinct from local keyboard focus.

  • descriptionPlacement?"end" | "inline"

    end (default) sets each description at the row's end. inline keeps the label at its own width and starts the description right after it, truncated, so long descriptions never push the row's text apart.

Full types: API reference.