Search bars are fine until someone hits Cmd/Ctrl+K. A command palette replaces hunting through menus with a keyboard-first layer that filters as you type โ and building one forces you to combine global keyboard handling, focus management and correct ARIA semantics in a single component.
๐งฉ Overview
Build a keyboard-driven command palette (Cmd/Ctrl+K) with fuzzy filtering, arrow-key navigation, a focus trap and proper combobox/listbox semantics.
๐ https://www.reactchallenges.com/challenges/command-palette
โ Requirements
- The palette is hidden on first render.
- Clicking the trigger opens the palette.
- Pressing Cmd/Ctrl+K opens the palette, and pressing it again closes it.
- Pressing Escape closes the palette.
- Clicking the backdrop closes the palette, while clicking inside the panel keeps it open.
- When the palette opens, the search input receives focus and is empty.
- The palette lists every command.
- Typing filters the commands by fuzzy match: every character of the query must appear in the label in order, ignoring case.
- When nothing matches, show
No results for "<query>". - Clearing the query restores the full list.
- The first command is highlighted when the palette opens and whenever the query changes.
- ArrowDown moves the highlight to the next command, wrapping from the last one to the first.
- ArrowUp moves the highlight to the previous command, wrapping from the first one to the last.
- Enter executes the highlighted command and closes the palette.
- Clicking a command executes it and closes the palette.
- Executing a command sets the
Last actiontext to that command's label. - While the palette is open, focus stays inside it when pressing Tab.
๐ก Notes
- Open and close from a single
windowkeydownlistener for Cmd/Ctrl+K and Escape, and callpreventDefault(). - Filter by subsequence, not
includes("gch" matches "Go to Challenges"), and resetactiveIndexwhen the query changes. - Focus the input on open and keep focus trapped inside the panel by listening for
focusin.
๐งช Tests
- keeps the palette hidden on first render
- opens the palette when the trigger is clicked
- opens the palette with Cmd/Ctrl+K
- focuses the search input when opened
- closes the palette when the shortcut is pressed again
- closes the palette on Escape
- closes the palette when the backdrop is clicked
- keeps the palette open when clicking inside the panel
- renders every command
- filters commands as the user types
- matches non-contiguous characters
- is case-insensitive
- shows a no-results message when nothing matches
- restores the full list when the query is cleared
- clears the query when the palette is reopened
- highlights the first command by default
- moves the highlight down with ArrowDown
- wraps from the first to the last with ArrowUp
- wraps from the last to the first with ArrowDown
- resets the highlight when the query changes
- executes the highlighted command with Enter
- executes a command when clicked
- traps focus inside the palette on Tab
If you want to practice keyboard-driven UI the way real apps do it, this challenge gives you the full loop: open, filter, navigate, execute and trap focus โ with 23 tests to keep you honest.
Top comments (0)