# Command Menu

A command palette with search and filtered rows.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md).

## Installation

<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>

```bash
npx shadcn@latest add @framecn/command-menu
```

<Step>Copy and paste the following code into your project.</Step>

<Step>Update the import paths to match your project setup.</Step>

## Usage

```tsx
import { CommandMenu } from "@/components/ui/command-menu";
```

```tsx
<div style={{ position: "relative", width: "100%", height: "100%" }}>
  <CommandMenu state="opened" query="set" />
</div>
```

Wrap in a positioned container — the panel and backdrop fill the composition.

## Smooth transitions

The docs preview opens the palette, types `"settings"` to filter the list, animates a row hover → press → selected, then closes. Drive the panel with `useCommandMenuTransition`, typing with `revealCount` from `@/lib/framecn-ui`, and row states with `useCommandMenuItemTransition`:

```tsx
import { useCurrentFrame, revealCount } from "@/lib/framecn-ui";
import { CommandMenu } from "@/components/framecn/command-menu";
import { useCommandMenuTransition } from "@/components/framecn/use-command-menu-transition";
import { useCommandMenuItemTransition } from "@/components/framecn/use-command-menu-item-transition";

const QUERY = "settings";
const TYPE_START = 20;

export const Scene = () => {
  const frame = useCurrentFrame();

  const panelStyle = useCommandMenuTransition([
    { at: 16, state: "opened", duration: 16 },
    { at: 108, state: "closed", duration: 12 },
  ]);

  const revealed = revealCount(
    Math.max(0, frame - TYPE_START),
    30,
    QUERY.length,
    4
  );

  const itemStyle = useCommandMenuItemTransition([
    { at: 84, state: "hover", duration: 8 },
    { at: 92, state: "press", duration: 6 },
    { at: 100, state: "selected", duration: 8 },
  ]);

  return (
    <div style={{ position: "relative", width: "100%", height: "100%" }}>
      <CommandMenu
        style={panelStyle}
        query={QUERY}
        revealCount={revealed}
        itemStyles={[itemStyle]}
      />
    </div>
  );
};
```

`style` takes precedence over `state` when both are provided. `itemStyles` is indexed into the **filtered** list.

## API Reference

### CommandMenu

| Prop               | Type                                    | Default                                  |
| ------------------ | --------------------------------------- | ---------------------------------------- |
| `state`            | `"opened" \| "closed"`                  | `"closed"`                               |
| `style`            | `CommandMenuStyle`                      | `-` (takes precedence over `state`)      |
| `query`            | `string`                                | `""`                                     |
| `revealCount`      | `number`                                | `-` (full `query` shown when omitted)    |
| `items`            | `CommandMenuEntry[]`                    | Profile, Settings, New File, Search docs |
| `selectedIndex`    | `number`                                | `-1`                                     |
| `highlightedIndex` | `number`                                | `-1`                                     |
| `pressedIndex`     | `number`                                | `-1`                                     |
| `itemStyles`       | `(CommandMenuItemStyle \| undefined)[]` | `-` (indexed into filtered list)         |
| `theme`            | `Partial<FramecnTheme>`                 | `-`                                      |
| `className`        | `string`                                | `-`                                      |