# React Command Palette: Cmd+K, Unterseiten und Mobile

> So baust du eine React Command Palette: Cmd+K auf dem Mac, Ctrl+K überall sonst, dazu Unterseiten, Async-Ergebnisse, Recents und ein Vollbild-Sheet am Handy.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 9. Okt. 2026
- Kategorie: [Komponenten-Guides](https://wingo-ui.com/de/blog/category/components)
- Lesezeit: 9 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/react-command-palette
- Englische Fassung: https://wingo-ui.com/blog/react-command-palette

## Kurz gesagt

Eine React Command Palette sollte einen einzigen mod+K-Shortcut binden, der auf Apple-Geräten ⌘K und sonst Ctrl+K anzeigt, Unterseiten als Stapel führen, den Backspace und Escape abbauen, Serversuchen entprellen und abbrechen und Recents über die ID des Eintrags speichern. Smartphones haben keine Cmd-Taste, also braucht sie auch einen sichtbaren Suchbutton, der ein Sheet in voller Höhe öffnet, mit bereits offener Tastatur und 16px Schrift im Eingabefeld. Das Command Menu von Wingo UI (Pro) erledigt all das auf Basis von cmdk; die Bausteine Kbd und useShortcut, die es nutzt, sind kostenlos.

Eine React Command Palette ist ein Suchfeld in einem Dialog. Damit springst du zu einer Seite, führst eine Aktion aus oder findest einen Kunden, ohne zur Maus zu greifen. Mit cmdk ist die erste Version schnell geschrieben. Die Details dauern länger: Der Hinweis muss auf dem Mac ⌘K und unter Windows Ctrl+K zeigen, „Theme…“ soll eine zweite Seite öffnen, die Backspace wieder schließt, Ergebnisse vom Server sollen ohne Flackern erscheinen, zuletzt Gewähltes soll oben stehen, und auf dem Handy soll das Ganze ein Sheet in voller Höhe mit offener Tastatur werden. Ein einfaches Beispiel für eine Cmd K Suche in React, auch das von shadcn, hört bei der gefilterten Liste auf. Dieser Guide behandelt den Rest mit dem [Command Menu](https://wingo-ui.com/components/command-menu) von Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral; Fakten von außen verlinken auf ihre Quellen.

## Was braucht ein React Command Menu?

Es braucht einen Shortcut, der das Gerät kennt, ein fehlertolerantes Ranking, Unterseiten, asynchrone Ergebnisse, Recents und ein Layout fürs Handy. Unsere Checkliste für ein React Command Menu:

- **Ein Shortcut, zwei Schreibweisen.** `mod+k` bindet ⌘K auf Apple-Geräten und Ctrl+K überall sonst, und der Hinweis zeigt die passende Variante.
- **Gruppen und Ranking.** Die Suche ignoriert Groß- und Kleinschreibung sowie diakritische Zeichen, „cafe“ findet also „Café“, und die passenden Buchstaben werden fett.
- **Unterseiten.** Ein Eintrag mit Chevron öffnet eine Seite; Backspace in einem leeren Eingabefeld oder Escape geht zurück.
- **Asynchrone Ergebnisse** unter den statischen, entprellt, die vorherige Anfrage wird abgebrochen.
- **Recents** über die ID des Eintrags, solange die Suche leer ist.
- **Smartphones**: ein Sheet in voller Höhe, 48px hohe Zeilen, ein Abbrechen-Button, keine Tastenhinweise.

```bash
npx wingo-ui@latest add command-menu
```

> Live-Demo (Command Menu): Drück ⌘J oder Ctrl+J (die Website behält ⌘K) oder klick ins Suchfeld, auf dem Handy ein Icon. Tipp „boston“ für Ergebnisse vom Server, wähl „Theme…“, um eine Seite zu öffnen, und drück dann Backspace, um zurückzugehen. Probier sie unter [Command Menu](https://wingo-ui.com/components/command-menu) aus und installier sie mit `npx wingo-ui@latest add command-menu`.

## Wie binde ich Cmd+K auf dem Mac und Ctrl+K unter Windows?

Schreib den Shortcut einmal als `mod+k`, mach aus `mod` auf Apple-Geräten Meta und sonst Control, vergleich die physische Taste, wenn die Tastaturbelegung ein anderes Zeichen erzeugt, und zeig das Label passend zum Gerät an. Das [Beispiel für die shadcn Command Palette](https://github.com/shadcn-ui/ui/blob/main/apps/v4/registry/new-york-v4/examples/command-dialog.tsx) schaltet mit dieser Prüfung um und zeigt fest verdrahtet ⌘J als Hinweis:

```tsx
if (e.key === "j" && (e.metaKey || e.ctrlKey)) {
  e.preventDefault()
  setOpen((open) => !open)
}
```

Drei Dinge stimmen hier nicht. Ctrl+J löst auch auf dem Mac aus. Windows-Nutzer sehen eine ⌘-Taste, die sie nicht haben. Und `event.key` ist das Zeichen, das die Tastaturbelegung erzeugt, auf einer kyrillischen Belegung also womöglich ein kyrillischer Buchstabe. [`event.code`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) benennt dagegen die physische Taste, und laut MDN ändert die Tastaturbelegung diesen Wert nicht. Der kostenlose [Hook useShortcut](https://wingo-ui.com/components/use-shortcut) löst alle drei Probleme, und die kostenlose Komponente [Kbd](https://wingo-ui.com/components/kbd) zeigt das Label an:

```tsx
"use client";

import { Kbd } from "@/components/ui/kbd";
import { useShortcut, useShortcutLabel } from "@/hooks/use-shortcut";

export function SearchButton({ onOpen }: { onOpen: () => void }) {
  const label = useShortcutLabel("mod+k");
  // meta auf apple-geräten, sonst ctrl; auf nicht-lateinischen layouts die physische taste
  useShortcut("mod+k", onOpen);
  return (
    <button type="button" onClick={onOpen} aria-keyshortcuts={label.aria}>
      Suche <Kbd shortcut="mod+k" hideOnTouch />
    </button>
  );
}
```

- **Auf dem Server erscheint das Label als Ctrl+K** und wechselt nach der Hydration zu ⌘K, denn der Server kennt die Plattform nicht. Das ist dieselbe Falle wie bei einem [SSR-sicheren useIsMobile-Hook](https://wingo-ui.com/de/blog/react-use-mobile-hook-ssr).
- **[`aria-keyshortcuts`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-keyshortcuts)** kündigt den Shortcut an. MDN weist darauf hin, dass das Attribut an der Funktion der Seite nichts ändert, der Listener erledigt also weiterhin die Arbeit.
- **Einzeltasten** wie `/` lösen nicht aus, solange der Fokus in einem Textfeld liegt. Kombinationen mit Modifier lösen überall aus.

Ctrl+K ist schon belegt: Laut [Chromes Liste der Tastenkürzel](https://support.google.com/chrome/answer/157179) startet Ctrl+K unter Windows und Linux von jeder Stelle der Seite aus eine Suche (Stand Oktober 2026). Der Listener ruft `preventDefault()` auf, also gewinnt die Palette, solange die Seite den Fokus hat. [MDN rät](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-keyshortcuts#dont_override_browser_assistive_technology_or_operating_system_shortcuts) davon ab, Browser-Shortcuts zu überschreiben, außer sie dienen demselben Zweck, und eine Suchpalette kommt dem nahe.

Ein Detail macht in cmdk React-Projekten unter Windows Ärger: Das Prop [`vimBindings`](https://github.com/dip/cmdk/blob/main/cmdk/src/index.tsx) steht standardmäßig auf true, also bewegen Ctrl+J und Ctrl+K in der Liste die Markierung und rufen `preventDefault()` auf. Ein Listener, der bereits behandelte Events überspringt, wie useShortcut, ignoriert dann das zweite Ctrl+K, und die Palette bleibt offen. Übergib `vimBindings={false}`, wenn Ctrl+K umschalten soll. Das Command Menu behält den Standard von cmdk (Stand Oktober 2026). Unter Windows und Linux bewegt ein zweites Ctrl+K also die Markierung nach oben, und Escape ist die Taste zum Schließen.

> Live-Demo (useShortcut): Drück Alt+K, auf dem Mac Option+K, wo diese Taste ˚ tippt: Die letzte Zeile leuchtet trotzdem auf, und die Zeile darunter schreibt die Kombination für beide Plattformen aus. Probier sie unter [useShortcut](https://wingo-ui.com/components/use-shortcut) aus und installier sie mit `npx wingo-ui@latest add use-shortcut`.

## Wie funktionieren Unterseiten in einer Command Palette?

Seiten sind ein Stapel. Ein Eintrag mit `page: "theme"` legt diese Seite auf den Stapel und leert die Suche. Backspace in einem leeren Eingabefeld oder Escape nimmt sie wieder herunter; Escape auf der ersten Seite schließt das Menü. Beim Zurückgehen kommt deine vorherige Suche wieder, und die Zeile, die die Seite geöffnet hat, ist markiert. Genau das überlässt dir [das Pages-Muster von cmdk](https://github.com/dip/cmdk). Eine Seite bringt eigene `groups` mit oder ein `loadItems`, das auch bei leerer Suche läuft (die Projektseite im vollständigen Beispiel unten).

## Wie lade ich asynchrone Ergebnisse ohne Flackern?

Entprell die Eingabe, brich die Anfrage ab, die sie ersetzt, und render Ergebnisse vom Server unter den lokalen, statt die Liste auszutauschen. Das Command Menu ruft `loadItems(query, { signal, page })` 200ms nach dem letzten Tastendruck auf (`debounce`), bricht den vorherigen Aufruf über `signal` ab, zeigt einen Spinner im Eingabefeld, lässt die statischen Treffer stehen und macht aus einem abgelehnten Promise eine Zeile „Could not load results“ mit „Try again“. Gib `signal` an `fetch` weiter, damit eine veraltete Anfrage stoppt.

Mit reinem cmdk setzt du `shouldFilter={false}`, wenn du selbst filterst oder der Server das schon getan hat. Sonst filtert und sortiert cmdk die Antwort des Servers ein zweites Mal. Das Command Menu setzt das Prop ebenfalls und sortiert mit einem eigenen Text-Matcher. Laut README hat cmdk außerdem keine Virtualisierung und bietet gute Performance bis 2.000 bis 3.000 Einträge. Große Datenmengen gehören also auf den Server.

## Wie sollten Recents in einer Command Palette funktionieren?

Speichere IDs, nie Labels, und nur für Dinge, die die Person ausgeführt hat. Gewählte Einträge landen im Local Storage unter `recentKey` (`"command-menu:recent"`), und die letzten `maxRecent` (5) erscheinen in einer Gruppe Recent, solange die Suche leer ist. Einträge, die eine Seite öffnen, werden nicht gespeichert. Ergebnisse vom Server bleiben nur für die aktuelle Sitzung in den Recents, denn nach einem Reload lassen sie sich nicht aus den statischen Gruppen rekonstruieren. Gib Server-IDs ein Präfix (`client:42`), damit sie nie mit statischen kollidieren: Teilen sich zwei Einträge eine ID, wird nur der erste gerendert, und Entwicklungs-Builds warnen vor Duplikaten in `groups` und `pages`.

## Was sollte eine Command Palette auf dem Handy tun?

Sie sollte ein Sheet in voller Höhe öffnen, mit bereits offener Tastatur. Ein Smartphone hat keine ⌘-Taste, also braucht die Palette einen sichtbaren Auslöser: `CommandMenuTrigger` zeigt auf dem Desktop „Search or jump to… ⌘K“ und schrumpft unter 768px zu einem Icon-Button. Unter 768px öffnet sich das Menü als [Bottom Sheet](https://wingo-ui.com/de/blog/react-bottom-sheet-for-the-web): ein Suchfeld im iOS-Stil, 48px hohe Zeilen, ein Abbrechen-Button, Wischen nach unten zum Schließen, und auf Touchscreens weder Tastenhinweise noch Footer.

Auf iOS fokussiert ein `focus()`-Aufruf, der nicht aus dem Tap kommt, zwar das Eingabefeld, lässt die Tastatur aber unten. Das ist Absicht: Im [WebKit-Bug 195884](https://bugs.webkit.org/show_bug.cgi?id=195884) schrieb ein Apple-Entwickler 2019, Apple wolle nicht, dass programmatischer Fokus die Tastatur einblendet, und der Bug ist im Oktober 2026 noch offen. Das Eingabefeld des Sheets existiert noch nicht, wenn der Tap ankommt. Deshalb fokussiert der Auslöser im Tap-Handler ein verstecktes Eingabefeld und gibt den Fokus an das echte weiter, sobald das Sheet gemountet ist.

Lass das Eingabefeld bei 16px. Safari auf iOS zoomt in ein fokussiertes Eingabefeld, dessen Text 15px oder kleiner ist ([CSS-Tricks](https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/)), und shadcns [`CommandInput`](https://github.com/shadcn-ui/ui/blob/main/apps/v4/registry/new-york-v4/ui/command.tsx) nutzt `text-sm` (14px), Stand Oktober 2026.

> Live-Demo (Command Menu): Diese Variante öffnet sich immer als Sheet fürs Handy. Klick ins Feld oder drück Alt+P (Option+P auf dem Mac), tipp „inv“ und drück dann „Cancel“ oder zieh das Sheet nach unten. Probier sie unter [Command Menu](https://wingo-ui.com/components/command-menu) aus und installier sie mit `npx wingo-ui@latest add command-menu`.

## Ist eine Command Palette mit cmdk barrierefrei?

Für das Kern-Widget ja. cmdk rendert das Eingabefeld als `combobox`, die eine `listbox` steuert, und setzt `aria-activedescendant` auf die markierte Option. Screenreader folgen also der markierten Zeile, während der Fokus im Eingabefeld bleibt. Laut README wurden Labels und ARIA-Attribute mit VoiceOver und den Chrome DevTools getestet. Das Command Menu ergänzt einen versteckten Dialogtitel, `aria-keyshortcuts` auf Zeilen mit Shortcut und eine Live-Region im Modus „polite“, die nach einer Tipppause die Zahl der Ergebnisse ansagt. Zum Übersetzen kommt der Text im Eingabefeld aus `placeholder`, `emptyText` und `loadingText`, jeder andere sichtbare oder vorgelesene Text aus `labels`.

## Solltest du die shadcn Command Palette, cmdk oder ein fertiges Menü nehmen?

Nimm shadcns Command, wenn du kostenlosen MIT-Code willst und Shortcut, Unterseiten, asynchrones Laden und das Handy-Layout selbst schreibst. Nimm cmdk direkt, wenn du eine Basis ohne Styles brauchst. Nimm das Command Menu, wenn du all das als Props haben willst. Stand Oktober 2026, laut [cmdk README](https://github.com/dip/cmdk) und der [Doku zu shadcn/ui Command](https://ui.shadcn.com/docs/components/command):

| | cmdk 1.1.1 | shadcn/ui Command | Wingo UI Command Menu |
| --- | --- | --- | --- |
| Was du bekommst | Primitives ohne Styles, `Command.Dialog` auf Radix | cmdk mit Tailwind-Styles in einem Dialog | Eine Komponente, über Props konfiguriert |
| Preis | Kostenlos, MIT | Kostenlos, MIT | Wingo UI Pro |
| Shortcut | Schreibst du selbst | Doku-Beispiel prüft Meta oder Ctrl + J | `shortcut="mod+k"`, Label je Gerät |
| Unterseiten | Ein Muster im README | Baust du selbst | `pages`, Breadcrumb, Zurück stellt die Zeile wieder her |
| Asynchrone Ergebnisse | `Command.Loading`; du lädst selbst | Baust du selbst | `loadItems`: Debounce, Abbruch, Retry |
| Recents | Nicht enthalten | Nicht enthalten | Über die ID gespeichert |
| Smartphones | Kein Layout | Zentrierter Dialog | Sheet in voller Höhe unter 768px |

Wenn deine Nutzer vor allem Datensätze suchen (Kunden, Rechnungen), mit Suchbereichen und Links „See all“, passt ein Feld im Header besser: [Global Search](https://wingo-ui.com/components/global-search) bindet `/`, gruppiert Ergebnisse nach Typ und öffnet sich auf dem Handy im Vollbild. Beides lässt sich kombinieren: `/` zum Suchen, ⌘K für Befehle.

## Wie baue ich eine React Command Palette in eine Next.js-App ein?

Installier sie, gib der Bibliothek einmal deinen Router und häng das Menü in die App-Shell. `LinkProvider` lässt Link-Zeilen über `next/link` rendern (Cmd+Klick öffnet also einen neuen Tab) und lässt Enter mit `router.push` navigieren:

```tsx
"use client";

import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { LinkProvider } from "@/lib/navigation";

export function Providers({ children }: { children: ReactNode }) {
  const router = useRouter();
  return (
    <LinkProvider component={Link} currentPath={usePathname()} navigate={router.push}>
      {children}
    </LinkProvider>
  );
}
```

Das Menü, mit Navigation, Aktionen, zwei Seiten und Serversuche:

```tsx
"use client";

import { FolderOpen, Moon, Sun, SunMoon, UserPlus } from "lucide-react";
import { useTheme } from "next-themes";
import { CommandMenu, CommandMenuTrigger, commandItemsFromNav, type CommandGroup, type CommandPage } from "@/components/ui/command-menu";
import type { NavItem } from "@/lib/navigation";

const nav: NavItem[] = [
  { label: "Kunden", href: "/clients" },
  { label: "Rechnungen", href: "/invoices", items: [{ label: "Überfällig", href: "/invoices/overdue" }] },
];

async function search<T>(url: string, signal: AbortSignal): Promise<T[]> {
  const res = await fetch(url, { signal });
  if (!res.ok) throw new Error(`Suche fehlgeschlagen: ${res.status}`);
  return res.json();
}

export function AppCommandMenu() {
  const { setTheme } = useTheme();

  const groups: CommandGroup[] = [
    { label: "Gehe zu", items: commandItemsFromNav(nav) },
    {
      label: "Aktionen",
      items: [
        { id: "new-client", label: "Neuer Kunde", icon: <UserPlus />, shortcut: "alt+n", href: "/clients/new" },
        { id: "open-project", label: "Projekt öffnen…", icon: <FolderOpen />, page: "projects" },
        { id: "theme", label: "Theme…", icon: <SunMoon />, page: "theme" },
      ],
    },
  ];

  const pages: CommandPage[] = [
    {
      id: "theme",
      title: "Theme",
      groups: [
        {
          items: [
            { id: "light", label: "Hell", icon: <Sun />, onSelect: () => setTheme("light") },
            { id: "dark", label: "Dunkel", icon: <Moon />, onSelect: () => setTheme("dark") },
          ],
        },
      ],
    },
    {
      id: "projects",
      title: "Projekte",
      placeholder: "Projekt finden…",
      // ein seiten-loader läuft auch bei leerer suche, die seite öffnet also mit einer liste
      loadItems: async (query, { signal }) => {
        const projects = await search<{ id: string; name: string }>(`/api/projects?q=${encodeURIComponent(query)}`, signal);
        return [{ items: projects.map((p) => ({ id: `project:${p.id}`, label: p.name, href: `/projects/${p.id}` })) }];
      },
    },
  ];

  return (
    <CommandMenu
      groups={groups}
      pages={pages}
      loadItems={async (query, { signal }) => {
        const clients = await search<{ id: string; name: string; city: string }>(`/api/clients?q=${encodeURIComponent(query)}`, signal);
        return [{ label: "Kunden", items: clients.map((c) => ({ id: `client:${c.id}`, label: c.name, description: c.city, href: `/clients/${c.id}` })) }];
      }}
      trigger={<CommandMenuTrigger />}
    />
  );
}
```

`commandItemsFromNav` macht aus den Einträgen deiner Sidebar Zeilen unter „Gehe zu“, verschachtelte lauten dann „Rechnungen › Überfällig“. Ein `onSelect`, das ein Promise zurückgibt, hält das Menü offen und zeigt auf dieser Zeile einen Spinner, bis es erledigt ist. Render `<AppCommandMenu />` im Header deiner App, innerhalb von `Providers` und dem `ThemeProvider` von next-themes, damit Link-Zeilen den Router erreichen und die Seite Theme das Farbschema wechseln kann.

Command Menu und Global Search gehören zu Wingo UI Pro, für 8 $ im Monat, 80 $ im Jahr oder einmalig 150 $, Stand Oktober 2026 ([Preise](https://wingo-ui.com/de/pricing)). Kbd und useShortcut sind kostenlos: `npx wingo-ui@latest add kbd use-shortcut`. Mehr findest du in den [Komponenten-Guides](https://wingo-ui.com/de/blog/category/components), zum Beispiel im [Guide zu React-Formularkomponenten](https://wingo-ui.com/de/blog/react-form-components-guide). Für ein Suchfeld in einem Formular statt eines globalen Menüs zeigt der [Guide zur React Combobox](https://wingo-ui.com/de/blog/react-combobox), wie asynchrone Suche ohne Race Conditions klappt.

## Komponenten in diesem Artikel

- [Command Menu](https://wingo-ui.com/components/command-menu) (Pro): A React command menu (⌘K palette) with groups, shortcuts, nested pages, async results and recents, and a full-height sheet on phones. Installation: `npx wingo-ui@latest add command-menu`
- [useShortcut](https://wingo-ui.com/components/use-shortcut) (Free): A React keyboard shortcut hook in mod+k notation: bind shortcuts, match events and show them as ⌘K on a Mac or Ctrl+K elsewhere. Installation: `npx wingo-ui@latest add use-shortcut`
- [Kbd](https://wingo-ui.com/components/kbd) (Free): A React kbd component for keyboard shortcuts, shown in the device's notation: ⌘K on a Mac, Ctrl+K everywhere else. Installation: `npx wingo-ui@latest add kbd`
- [Global Search](https://wingo-ui.com/components/global-search) (Pro): A React global search bar for an app header: grouped results from every entity as you type, scopes, recents and suggestions, full screen on phones. Installation: `npx wingo-ui@latest add global-search`

## Häufige Fragen

### Wie öffne ich in React eine Command Palette mit Cmd+K?

Registrier einen keydown-Listener auf window und schalte die Palette um, wenn auf Apple-Geräten Meta und K, sonst Control und K gedrückt werden. Ruf dann preventDefault auf, damit die eigene Ctrl+K-Suche des Browsers nicht startet. Der kostenlose Hook useShortcut von Wingo UI, aufgerufen als useShortcut("mod+k", toggle), übernimmt die Plattformprüfung und erkennt auf nicht-lateinischen Layouts auch die physische K-Taste.

### Filtert cmdk asynchrone Ergebnisse?

Ja, standardmäßig filtert und sortiert cmdk jeden gerenderten Eintrag, auch Ergebnisse vom Server. Setz shouldFilter={false} auf Command, wenn du selbst filterst oder der Server schon passende Treffer liefert, und render Command.Loading, solange die Anfrage läuft.

### Wie viele Einträge schafft cmdk?

Laut README hat cmdk keine Virtualisierung und bleibt bis 2.000 bis 3.000 Einträge performant. Bei mehr Einträgen suchst du besser auf dem Server und lieferst nur die besten Treffer zurück.

### Warum schließt ein zweites Ctrl+K meine cmdk-Palette unter Windows nicht?

Das Prop vimBindings von cmdk steht standardmäßig auf true, also bewegen Ctrl+J und Ctrl+K in der Palette die Markierung und rufen preventDefault auf. Ein Shortcut-Listener, der bereits behandelte Events überspringt, ignoriert den Tastendruck dann. Übergib vimBindings={false}, wenn Ctrl+K umschalten soll.

### Wie sollte eine Command Palette auf dem Handy funktionieren?

Gib ihr einen sichtbaren Suchbutton, denn Smartphones haben keine Cmd-Taste, und öffne sie als Sheet in voller Höhe. Fokussiere das Eingabefeld noch im Tap, damit iOS die Tastatur einblendet. Nutze 16px Schrift im Eingabefeld, damit Safari nicht zoomt, und Zeilen mit mindestens 44px Höhe.

### Ist das Command Menu von Wingo UI kostenlos?

Nein. Command Menu und Global Search gehören zu Wingo UI Pro. Die Komponente Kbd und der Hook useShortcut sind kostenlos und lassen sich mit npx wingo-ui@latest add kbd use-shortcut installieren.

---

Quelle: https://wingo-ui.com/de/blog/react-command-palette
