# ui/slash

> Slash menu — "/" opens a menu built from `registry.slash`: every module contributes its own entries, so registering a module is all it takes to appear.

Slash menu (F-40) — "/" opens a menu built from `registry.slash`: every module contributes its own entries, so registering a module is all it takes to appear. Filters on label and keywords; ↑ ↓ ⏎ Tab and Esc drive it. Choosing removes the "/query" text in the same undo step. `menu()` is the same trigger menu for other characters (the emoji picker uses ":").

```js
import slash from 'verbal-editor/ui/slash';
```

| JS gzip | CSS gzip |
| --- | --- |
| 1.36 KB | 0.49 KB |

See it live on [Writing](#/examples/welcome) — every example page on the landing is editable.

## Contract

|  |  |
| --- | --- |
| Name | `slash` |

## Acceptance

| Feature | Acceptance | Budget |
| --- | --- | --- |
| F-40 · Slash commands | Registering a module makes it appear with zero edits elsewhere; keyboard-navigable; filters on label and keywords | ≤ 2KB |

## API

### `menu(editor, { char, label, items, pick })`

A menu that opens when `char` is typed at the start of a word, ranks `items(query)` as you type and closes on whitespace with no match.

| Parameter | Type | Description |
| --- | --- | --- |
| `editor` | `import('../../index.js').Editor` | — |
| `options` | `{ char: string, label: string, items: (q: string) => Entry[] \| Promise<Entry[]>, pick: (entry: Entry, t: any, at: { block: string, offset: number }) => void }` | `pick` runs with the "<char>query" text already deleted in `t`. |

Returns `() => void` — cleanup.
