React Command Palette: Cmd+K, Unterseiten und Mobile

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 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+kbindet ⌘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.
$ npx wingo-ui@latest add command-menuWie 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 (opens in a new tab) schaltet mit dieser Prüfung um und zeigt fest verdrahtet ⌘J als Hinweis:
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 (opens in a new tab) benennt dagegen die physische Taste, und laut MDN ändert die Tastaturbelegung diesen Wert nicht. Der kostenlose Hook useShortcut löst alle drei Probleme, und die kostenlose Komponente Kbd zeigt das Label an:
- 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.
aria-keyshortcuts(opens in a new tab) 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 (opens in a new tab) 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 (opens in a new tab) 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 (opens in a new tab) 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.
$ npx wingo-ui@latest add use-shortcutWie 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 (opens in a new tab). 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: 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 (opens in a new tab) 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 (opens in a new tab)), und shadcns CommandInput (opens in a new tab) nutzt text-sm (14px), Stand Oktober 2026.
$ npx wingo-ui@latest add command-menuIst 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 (opens in a new tab) und der Doku zu shadcn/ui Command (opens in a new tab):
Wenn deine Nutzer vor allem Datensätze suchen (Kunden, Rechnungen), mit Suchbereichen und Links „See all“, passt ein Feld im Header besser: 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:
Das Menü, mit Navigation, Aktionen, zwei Seiten und Serversuche:
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). Kbd und useShortcut sind kostenlos: npx wingo-ui@latest add kbd use-shortcut. Mehr findest du in den Komponenten-Guides, zum Beispiel im Guide zu React-Formularkomponenten. Für ein Suchfeld in einem Formular statt eines globalen Menüs zeigt der Guide zur React Combobox, wie asynchrone Suche ohne Race Conditions klappt.
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.
- Command Palette
- Tastenkürzel
- cmdk
- Mobile UI
- Barrierefreiheit


