|
| 1 | +# @mattis/react-command-palette |
| 2 | + |
| 3 | +A flexible, accessible command palette component for React applications. Provide instant keyboard-driven navigation, run custom actions, and surface global shortcuts with a single provider. |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +## Table of Contents |
| 12 | +- [Features](#features) |
| 13 | +- [Installation](#installation) |
| 14 | +- [Quick Start](#quick-start) |
| 15 | +- [Configuring Commands](#configuring-commands) |
| 16 | +- [Customising the Palette](#customising-the-palette) |
| 17 | +- [Keyboard Shortcuts](#keyboard-shortcuts) |
| 18 | +- [Documentation](#documentation) |
| 19 | +- [Development](#development) |
| 20 | +- [Contributing](#contributing) |
| 21 | + |
| 22 | +## Features |
| 23 | +- **Drop-in provider** – Wrap your app with `CommandPaletteProvider` to make the palette available everywhere. |
| 24 | +- **Async-ready commands** – Load commands from APIs or other async sources with built-in debounce handling. |
| 25 | +- **Global command modes** – Offer alternative contexts (like GitHub-style `/` search) with prefixes and helper text. |
| 26 | +- **Design flexibility** – Override every part of the UI with inline styles, helper hints, and layout options. |
| 27 | +- **Accessible interactions** – Keyboard navigation, focus management, and customisable shortcuts keep power users in flow. |
| 28 | + |
| 29 | +## Installation |
| 30 | + |
| 31 | +Install the package from npm: |
| 32 | + |
| 33 | +```bash |
| 34 | +npm install @mattis/react-command-palette |
| 35 | +``` |
| 36 | + |
| 37 | +This library follows React 19’s peer dependency requirements. Ensure your project already depends on `react` and `react-dom`. |
| 38 | + |
| 39 | +## Quick Start |
| 40 | + |
| 41 | +```tsx |
| 42 | +import { CommandPaletteProvider, SHORTCUTS, type Command } from "@mattis/react-command-palette"; |
| 43 | + |
| 44 | +const commands: Command[] = [ |
| 45 | + { |
| 46 | + id: "open-settings", |
| 47 | + label: "Open Settings", |
| 48 | + category: "Navigation", |
| 49 | + action: () => alert("Settings opened"), |
| 50 | + }, |
| 51 | + { |
| 52 | + id: "create-project", |
| 53 | + label: "Create Project", |
| 54 | + category: "Actions", |
| 55 | + action: () => alert("New project created"), |
| 56 | + keywords: ["new", "add"], |
| 57 | + }, |
| 58 | +]; |
| 59 | + |
| 60 | +export function App() { |
| 61 | + return ( |
| 62 | + <CommandPaletteProvider commands={commands} shortcut={SHORTCUTS.COMMAND}> |
| 63 | + <YourApplication /> |
| 64 | + </CommandPaletteProvider> |
| 65 | + ); |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +Wrap your routes or layout with the provider to expose the palette. Users can open it with `⌘K` / `Ctrl+K` by default. |
| 70 | + |
| 71 | +## Configuring Commands |
| 72 | + |
| 73 | +Commands are simple objects describing how each item should behave: |
| 74 | + |
| 75 | +```ts |
| 76 | +import type { Command } from "@mattis/react-command-palette"; |
| 77 | + |
| 78 | +type Command = { |
| 79 | + id: string; |
| 80 | + icon?: React.ReactNode; |
| 81 | + label: string; |
| 82 | + action?: () => void; |
| 83 | + category: string; |
| 84 | + keywords?: string[]; |
| 85 | + helper?: string; |
| 86 | +}; |
| 87 | +``` |
| 88 | + |
| 89 | +You can provide commands in three different ways: |
| 90 | + |
| 91 | +1. **Static array** – Pass an array of command objects via the `commands` prop. |
| 92 | +2. **Async function** – Provide a `(query: string) => Promise<Command[]>` to fetch on demand. The query is debounced by default for smoother UX. |
| 93 | +3. **Promise** – Supply a promise that resolves to a command list when the palette mounts. |
| 94 | + |
| 95 | +### Global commands |
| 96 | + |
| 97 | +Use the `globals` prop to define prefix-driven modes, such as `/` to search across entities. These commands appear when the user types the shortcut prefix: |
| 98 | + |
| 99 | +```tsx |
| 100 | +<CommandPaletteProvider |
| 101 | + commands={fetchCommands} |
| 102 | + globals={{ |
| 103 | + shortcut: "/", |
| 104 | + label: "Global Commands", |
| 105 | + commands: [ |
| 106 | + { id: "search-users", label: "Search users", category: "Global", action: () => alert("Searching users…") }, |
| 107 | + { id: "search-repos", label: "Search repositories", category: "Global", action: () => alert("Searching repos…") }, |
| 108 | + ], |
| 109 | + }} |
| 110 | +> |
| 111 | + {children} |
| 112 | +</CommandPaletteProvider> |
| 113 | +``` |
| 114 | + |
| 115 | +## Customising the Palette |
| 116 | + |
| 117 | +Pass a `CommandPaletteOptions` object through the `options` prop to tweak the UI or behaviour. Every key accepts inline `CSSProperties` so you can integrate with your design system without maintaining extra CSS files. |
| 118 | + |
| 119 | +```tsx |
| 120 | +import type { CommandPaletteOptions } from "@mattis/react-command-palette"; |
| 121 | + |
| 122 | +const options: CommandPaletteOptions = { |
| 123 | + containerStyle: { |
| 124 | + backgroundColor: "#0d1117", |
| 125 | + border: "1px solid #30363d", |
| 126 | + borderRadius: "12px", |
| 127 | + }, |
| 128 | + containerInputFieldStyle: { |
| 129 | + padding: "0.5rem 1rem", |
| 130 | + }, |
| 131 | + itemStyle: { |
| 132 | + padding: "0.75rem 1rem", |
| 133 | + borderRadius: "8px", |
| 134 | + }, |
| 135 | + helper: [ |
| 136 | + { text: "Press", keys: ["Enter"], description: "to run a command" }, |
| 137 | + ], |
| 138 | + closeOnSelect: false, |
| 139 | +}; |
| 140 | +``` |
| 141 | + |
| 142 | +Key highlights: |
| 143 | + |
| 144 | +- **`closeOnSelect`** defaults to `true`. Set it to `false` to keep the palette open after running a command—useful for bulk actions. |
| 145 | +- **`helper` hints** display contextual keyboard tips below the input. |
| 146 | +- **Style overrides** exist for the container, list, items, overlay, categories, and more. |
| 147 | + |
| 148 | +Explore `docs/guide/customize.md` for a complete breakdown of available options. |
| 149 | + |
| 150 | +## Keyboard Shortcuts |
| 151 | + |
| 152 | +The provider ships with a `SHORTCUTS` helper for common key combos (`⌘K`, `Ctrl+Shift+P`, etc.). You can also pass a custom shortcut definition: |
| 153 | + |
| 154 | +```tsx |
| 155 | +<CommandPaletteProvider |
| 156 | + commands={commands} |
| 157 | + shortcut={{ combo: "Ctrl+Shift+P", description: "Open command palette" }} |
| 158 | +/> |
| 159 | +``` |
| 160 | + |
| 161 | +Pressing `Esc` always closes the palette. You can interact with the imperative API via the `apiRef` prop if you need programmatic control. |
| 162 | + |
| 163 | +## Documentation |
| 164 | + |
| 165 | +Full usage guides, API references, and walkthroughs live in the [`docs/`](./docs) directory. You can run the VitePress site locally: |
| 166 | + |
| 167 | +```bash |
| 168 | +npm run docs:dev |
| 169 | +``` |
| 170 | + |
| 171 | +## Development |
| 172 | + |
| 173 | +Clone the repository and install dependencies: |
| 174 | + |
| 175 | +```bash |
| 176 | +npm install |
| 177 | +``` |
| 178 | + |
| 179 | +Available scripts: |
| 180 | + |
| 181 | +- `npm run dev` – Build the library in watch mode with tsup. |
| 182 | +- `npm run build` – Generate the production bundles in `dist/`. |
| 183 | +- `npm run docs:dev` – Start the docs site locally. |
| 184 | +- `npm run docs:build` – Build the static documentation site. |
| 185 | +- `npm run docs:preview` – Preview the generated docs output. |
| 186 | + |
| 187 | +Before publishing, ensure the build passes and that `dist/` reflects the latest compiled output. |
| 188 | + |
| 189 | +## Contributing |
| 190 | + |
| 191 | +Issues and pull requests are welcome! |
| 192 | +If you’re planning a large contribution, open an issue to discuss your idea first. Follow the existing code style (TypeScript, hooks-based React) and include updates to the documentation when behaviour changes. |
0 commit comments