Components
CommandPalette
A ⌘K palette with local entries and server-side search.
A ⌘K command palette: jumping to sections, searching your data and launching actions, all from one input.
Try it
Arrows move through the list, Enter opens, Escape closes. Hovering with the mouse moves the same cursor the keyboard does — they never fight over the selection.
Local entries
Application sections and commands need no request — they are filtered in place by title and hidden keywords:
import { CommandPalette } from "@toimetdev/pathlogs-core";
<CommandPalette
items={[
{ id: "dashboard", group: "Navigation", title: "Projects", hint: "g d",
onSelect: () => router.push("/dashboard") },
{ id: "new", group: "Actions", title: "New task",
keywords: "create add issue",
onSelect: () => setNewTaskOpen(true) },
]}
labels={{ placeholder: "Search projects, tasks, sections…", empty: "Nothing found" }}
/>The default shortcut is mod+k. The palette registers it itself; pass hotkey={null} if you drive opening from outside.
Server-side search
Everything that is not on the client comes from the search function. It is called with a delay after typing — while the user is still typing, the intermediate substrings are of no use to anyone:
<CommandPalette
items={navItems}
search={async (query) => {
const { projects, tasks } = await searchAction(query);
return [
...projects.map((p) => ({
id: `p:${p.id}`, group: "Projects", title: p.name, badge: p.key,
onSelect: () => router.push(`/projects/${p.id}`),
})),
...tasks.map((t) => ({
id: `t:${t.id}`, group: "Tasks", title: t.title,
badge: `${t.projectKey}-${t.number}`,
onSelect: () => router.push(`/tasks/${t.id}`),
})),
];
}}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | CommandItem[] | [] | Entries available without a request. Filtered by title and keywords. |
search | (query: string) => Promise<CommandItem[]> | — | The source of results from the server. |
debounce | number | 150 | Delay before the request, ms. |
hotkey | string | null | "mod+k" | The opening shortcut. null means external control only. |
open / onOpenChange | boolean / (open: boolean) => void | — | External control. Without them the palette keeps its own state. |
labels | { placeholder, empty, navigate, select } | — | Captions. English by default. |
itemsCommandItem[]defaults to: []
Entries available without a request. Filtered by title and keywords.
search(query: string) => Promise<CommandItem[]>The source of results from the server.
debouncenumberdefaults to: 150
Delay before the request, ms.
hotkeystring | nulldefaults to: "mod+k"
The opening shortcut. null means external control only.
open / onOpenChangeboolean / (open: boolean) => voidExternal control. Without them the palette keeps its own state.
labels{ placeholder, empty, navigate, select }Captions. English by default.
A list entry:
interface CommandItem {
id: string;
title: string;
group?: string; // section heading; entries group in order of appearance
badge?: string; // a short label on the left: project key, task number
hint?: string; // a hint on the right: the entry's own shortcut
icon?: ReactNode;
keywords?: string; // extra text for searching, never displayed
onSelect: () => void;
}