Code

js/shortcuts.js — one listener for every key

In the code column — js/shortcuts.js. It's a perfect delegation example: one listener on document serves every keyboard shortcut. We don't add a listener per key — we let events bubble up to document and decide there what to do.

How it works: register('g', () => navigate('/gallery')) remembers a key; initShortcuts() listens for keydown on document and, on a match, calls the handler.

Two decisions matter here (both real UX questions):

  • Don't steal keys while the user is typing. isTyping(e.target) checks whether focus is in an input field. If so — we skip (so / in the search box types a slash instead of opening search). The exception is Escape, which should always "get out".
  • Don't fight the browser. If Ctrl/Cmd/Alt is held — skip, so we don't hijack Ctrl+F, Cmd+R and friends.
document.addEventListener('keydown', (e) => {
  if (isTyping(e.target)) { if (e.key === 'Escape') e.target.blur(); return; }
  if (e.metaKey || e.ctrlKey || e.altKey) return;
  const entry = shortcuts.get(e.key.toLowerCase());
  if (entry) { e.preventDefault(); entry.handler(e); }
});

Notice e.preventDefault() — when the key is ours, we stop the browser's default so that, say, / doesn't open the browser's own find bar.

Tip. This pattern — "one listener, a map of actions" — recurs everywhere: keyboard, list clicks, menus. Instead of adding N listeners (and cleaning them up), you add one on the parent. Less code, fewer memory leaks, and it works for content added dynamically too.