key vs code vs keyCode — the three identities of a keypress
Press one key and the event carries several different descriptions of it. Knowing which to read is most of the battle:
| Property | Tells you | Layout-dependent? | Status |
|---|---|---|---|
event.key | The character/value produced ("a", "A", "Enter") | Yes | Use this |
event.code | The physical key position ("KeyA", "Space") | No | Use this |
event.keyCode | Legacy numeric code | Yes | Deprecated |
keyCode is deprecated and shouldn’t be used in new code, but it’s still shown here for maintaining legacy systems. For everything new, it’s key (what was typed) and code (which physical key) — and the FAQ above explains which to pick.
Detecting combinations
A shortcut like Ctrl+Shift+S is just a key/code check combined with the modifier booleans the event always carries: event.ctrlKey, event.shiftKey, event.altKey, and event.metaKey (Command on macOS, Windows key on Windows). This viewer generates the exact condition for whatever combination you press, including the cross-platform nuance that “Ctrl” on Windows is often “Cmd” (metaKey) on macOS — a detail that trips up a lot of shortcut code.
Why some keys never reach your handler
If a key seems “dead,” it may be intercepted before JavaScript sees it. PrintScreen is grabbed by the OS, F11 toggles browser fullscreen, and Ctrl+W closes the tab — and preventDefault() can’t always override these reserved combinations. When designing shortcuts, prefer combinations (Ctrl+Shift+letter) that browsers don’t already claim, and test on the platforms you support, since the reserved set differs between OSes and browsers.
The focus gotcha
Key events fire on the focused element first. A document-level listener may not behave as expected when an <input>, <textarea>, or contenteditable has focus and consumes the event. For global shortcuts, check event.target.tagName to decide whether to act or defer, or attach the listener with { capture: true } to see the event on the way down. Combined with the isComposing guard above, that’s the recipe for shortcuts that don’t fight with text entry.