Power users expect keyboard shortcuts. Linear has hundreds; Notion many; Gmail famously does. The interview tests whether you understand the registration patterns, scope handling, and conflict resolution.
Functional requirements
- Register shortcuts globally and per-component
- Detect modifier keys (Cmd, Ctrl, Shift, Alt)
- Handle key combinations (Cmd+Shift+K)
- Don’t fire when user is typing in an input
- Show shortcut hints (next to menu items, in command palette)
- Help dialog showing all shortcuts (?)
Architecture
Two pieces:
- Global event listener on keydown — one listener attached at the document or window level so shortcuts work no matter what’s focused. Attaching a listener per component instead leads to duplicate handlers and events that get missed depending on focus.
- Registry of shortcut → handler mappings — a central map keyed by a normalized combo (like
cmd+k) that the single listener consults on each keypress. Centralizing it lets you detect duplicate combos, generate the help dialog from one source, and enable or disable groups by scope.
Library: react-hotkeys-hook
The standard React option:
useHotkeys('cmd+k', (e) => {
e.preventDefault();
openCommandPalette();
});
Cross-platform: cmd maps to Cmd on Mac, Ctrl on Windows/Linux.
Detecting modifier keys
Cross-platform detection:
- Mac:
e.metaKeyfor Cmd - Windows/Linux:
e.ctrlKeyfor Ctrl - Convention: “Cmd/Ctrl” handled by libraries automatically
Don’t fire in inputs
Critical UX: typing “k” in an input should not trigger Cmd+K shortcut’s “k” component.
Check event target:
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.isContentEditable) {
return; // ignore
}
Exception: shortcuts with modifiers (Cmd+S, Cmd+Z) should fire even in inputs.
Scopes
Different shortcuts in different parts of the app:
- Global: always active (Cmd+K, Esc) — these fire regardless of focus, so keep the set small and stable to avoid surprising the user.
- Modal: only when modal is open — bind these when the modal mounts and unbind on close, so Esc closes the modal without also firing a global handler underneath it.
- Editor: only when editor focused — activate the editor’s shortcut set on focus and tear it down on blur, otherwise formatting keys like Cmd+B leak into the rest of the app.
Scope-aware libraries enable/disable based on focus.
Conflict resolution
Two shortcuts on the same key. Strategies:
- Most-recently-registered wins — a simple stack where the last handler bound for a key shadows earlier ones; predictable, but a stale registration you forgot to unbind can quietly hide a global shortcut.
- Most-specific scope wins (modal beats global) — resolve by scope depth so the innermost active context handles the key first, which matches what users expect (Esc closes the open dialog, not the page).
- Explicit priority numbers — attach a priority to each binding and sort on it; the most flexible option, but you have to keep the numbers coherent as the app grows.
Sequence shortcuts
Some apps support multi-key sequences (Vim-style):
- “g, i” → go to inbox
- “g, p” → go to projects
Implementation: track previous key with timeout (~1 second).
Display
Show shortcut hints visibly:
- Next to menu items: “Edit (E)”
- In tooltips: “Save (Cmd+S)”
- In command palette results
Use <kbd> for visual styling.
Help dialog
“?” key (or Cmd+/) opens a dialog listing all shortcuts. Standard UX:
- Grouped by category (Navigation, Actions, Editing)
- Each row: shortcut + description
- Search to filter
Accessibility
- Don’t conflict with browser shortcuts (don’t override Cmd+T, Cmd+W) — you often can’t reliably preventDefault these anyway, and hijacking them breaks the user’s muscle memory. Interviewers like to hear you name the reserved combos you deliberately avoid.
- Don’t conflict with screen-reader shortcuts — screen readers reserve many keys (arrows, single letters in browse mode); single-key shortcuts are the worst offenders, so prefer modified combos or scope single keys tightly.
- Provide alternative interactions (mouse-clickable equivalent) — every shortcut should map to a visible control, so the action stays discoverable and usable without a keyboard.
- Document all shortcuts — surface them in the help dialog and in tooltips so keyboard-only and assistive-tech users can actually find them.
Common antipatterns
- Shortcut fires while typing in input — the most common bug; guard on the event target’s tag name and
isContentEditablebefore dispatching. - Different platforms have different shortcuts (mismatched Cmd/Ctrl) — hardcoding
metaKeybreaks Windows users; normalize to a “mod” key that maps to Cmd on Mac and Ctrl elsewhere. - No way for users to discover shortcuts — without hints and a help dialog, only power users who read docs benefit; show the combo next to the menu item that triggers it.
- Conflicting shortcuts (two handlers for same key) — pick a resolution strategy up front instead of relying on registration order by accident.
Frequently Asked Questions
Should I support customizable shortcuts?
For power-user apps (IDEs, design tools): yes. For typical SaaS: defaults are usually enough.
How do I handle international keyboards?
Use e.code (physical key) instead of e.key for layout-independence. Trade-off: French AZERTY users get the same physical-key shortcuts as US QWERTY, even if labels differ.
Can shortcuts work on mobile?
Bluetooth keyboards yes. On-screen keyboards: no — there are no Cmd/Ctrl keys. Provide button alternatives.
Useful next steps:
