CommandPalette
Import
Section titled “Import”import { CommandPalette } from '@delightstack/components';Basic Usage
Section titled “Basic Usage”View code
<script> import { CommandPalette, Button } from '@delightstack/components';
let open = $state(false);
const commands = [ { id: 'new', title: 'New File', category: 'File', shortcut: ['Ctrl', 'N'], onselect: () => {} }, { id: 'save', title: 'Save', category: 'File', shortcut: ['Ctrl', 'S'], onselect: () => {} }, { id: 'copy', title: 'Copy', category: 'Edit', shortcut: ['Ctrl', 'C'], onselect: () => {} }, { id: 'theme', title: 'Toggle Theme', category: 'View', onselect: () => {} }, ];</script>
<Button onclick={() => open = true}>Open Command Palette</Button><CommandPalette bind:open {commands} placeholder="Search commands..." /><script> import { CommandPalette } from '@delightstack/components';
let paletteOpen = $state(false);
const commands = [ { id: 'settings', title: 'Settings', description: 'Open application settings', category: 'Navigation', onselect: () => goto('/settings') } ];</script>
<CommandPalette bind:open={paletteOpen} {commands} />The palette automatically registers a global Ctrl/Cmd + K keyboard shortcut to toggle visibility.
Examples
Section titled “Examples”Full Command Setup
Section titled “Full Command Setup”<script> import { CommandPalette } from '@delightstack/components'; import { goto } from '$app/navigation'; import PlusIcon from '~icons/mdi/plus'; import SettingsIcon from '~icons/mdi/cog'; import ThemeIcon from '~icons/mdi/brightness-6';
let paletteOpen = $state(false);
const commands = [ { id: 'new-project', title: 'New Project', description: 'Create a new project', category: 'Projects', icon: PlusIcon, shortcut: ['Ctrl', 'N'], onselect: () => goto('/projects/new') }, { id: 'settings', title: 'Settings', description: 'Open application settings', category: 'Navigation', icon: SettingsIcon, shortcut: ['Ctrl', ','], onselect: () => goto('/settings') }, { id: 'theme-toggle', title: 'Toggle Theme', description: 'Switch between light and dark mode', category: 'Preferences', icon: ThemeIcon, keywords: ['dark', 'light', 'appearance'], onselect: () => toggleTheme() } ];</script>
<CommandPalette bind:open={paletteOpen} {commands} />Compact / Dense Mode
Section titled “Compact / Dense Mode”Use dense for tighter spacing in smaller interfaces.
View code
<CommandPalette bind:open={paletteOpen} {commands} dense />Roomy / Comfortable Mode
Section titled “Roomy / Comfortable Mode”Use comfortable for more generous spacing and larger tap targets — handy on
touch interfaces or when the palette is the primary surface.
View code
<CommandPalette bind:open={paletteOpen} {commands} comfortable />Without Category Grouping
Section titled “Without Category Grouping”Disable grouping to show a flat list of results.
View code
<CommandPalette bind:open={paletteOpen} {commands} group_by="none" />With Selection Callback
Section titled “With Selection Callback”Track when any command is selected using the onselect prop.
<CommandPalette bind:open={paletteOpen} {commands} onselect={(command) => { analytics.track('command_used', { id: command.id }); }}/>Promise-Aware Commands
Section titled “Promise-Aware Commands”When a command’s onselect returns a Promise, a spinner appears while executing. On success, the palette closes. On failure, it stays open.
const commands = [ { id: 'sync', title: 'Sync Data', description: 'Synchronize with the server', onselect: async () => { await api.syncAll(); } }];Custom Placeholder
Section titled “Custom Placeholder”<CommandPalette bind:open={paletteOpen} {commands} placeholder="Search commands, pages, or settings..."/>| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Controls visibility ($bindable()) |
commands | CommandOption[] | [] | Available commands to search |
placeholder | string | 'Type a command or search...' | Input placeholder text |
recent_limit | number | 5 | Number of recent items to show when input is empty |
group_by | 'category' | 'none' | 'category' | How to group results |
dense | boolean | false | Compact result item spacing |
comfortable | boolean | false | Roomy result item spacing |
onselect | (command: CommandOption) => void | undefined | Called when any command is selected |
id | string | auto-generated | Element ID |
class | string | '' | Additional CSS classes |
Events
Section titled “Events”| Event | Detail | Description |
|---|---|---|
onselect | CommandOption | Fires when a command is selected, before executing command.onselect |
interface CommandOption { /** Unique identifier for the command */ id: string;
/** Display title of the command */ title: string;
/** Optional description shown below the title */ description?: string;
/** Category for grouping commands */ category?: string;
/** Optional icon component */ icon?: Component;
/** Keyboard shortcut keys to display (e.g. ['Ctrl', 'K']) */ shortcut?: string[];
/** Additional search keywords */ keywords?: string[];
/** Whether the command is disabled */ disabled?: boolean;
/** Called when the command is selected */ onselect: () => void | Promise<void>;}Keyboard Navigation
Section titled “Keyboard Navigation”| Key | Action |
|---|---|
Ctrl/Cmd + K | Toggle open (global shortcut) |
Arrow Up / Arrow Down | Navigate results |
Enter | Execute selected command |
Escape | Close palette |
Fuzzy Search
Section titled “Fuzzy Search”The palette uses a built-in fuzzy search engine that scores matches across title, description, category, and keywords fields. Matching characters in the title are highlighted in the results.
Scoring priority: exact match > starts with > word boundary match > contains > fuzzy character match. Title matches are weighted highest, followed by keywords, description, and category.
Recent Commands
Section titled “Recent Commands”Recently used commands are tracked in memory and shown when the input is empty. The list is sorted by recency and limited by the recent_limit prop.
Accessibility
Section titled “Accessibility”- ARIA combobox pattern (
role="combobox"on input,role="listbox"on results) aria-activedescendanttracks the highlighted resultaria-expandedreflects whether results are visiblearia-autocomplete="list"on the inputrole="option"witharia-selectedandaria-disabledon each result item- Focus trap keeps focus within the palette while open
- Input is always focused while the palette is open