JavaScript Notes
Master JavaScript keyboard events: keydown, keyup, keypress, key properties, shortcuts, and real-world examples with outputs. Complete guide 2026.
Introduction
Keyboard events are fired when a user interacts with the keyboard. Whether the user is typing in a text field, pressing Enter to submit a form, using Ctrl+S to save, or navigating with arrow keys — keyboard events give you full control over these interactions.
There are three primary keyboard events in JavaScript:
keydown– Fires when a key is pressed downkeyup– Fires when a key is releasedkeypress– ⚠️ Deprecated (don't use in new code)
Keyboard events are essential for building:
- Form validation and submission
- Keyboard shortcuts (like Ctrl+C, Ctrl+V)
- Game controls (arrow keys, WASD)
- Accessible navigation
- Custom text editors
- Search-as-you-type features
These events belong to the KeyboardEvent interface, which provides many useful properties such as key, code, ctrlKey, shiftKey, etc.
Types of Keyboard Events
1. keydown Event
The keydown event fires when ANY key is pressed — including modifier keys (Shift, Ctrl, Alt), function keys (F1-F12), arrow keys, and character keys.
Key Features:
- Fires for ALL keys (character + non-character)
- Fires repeatedly when key is held down
- Best for detecting shortcuts and navigation
- Can prevent default behavior
2. keyup Event
The keyup event fires when a key is released.
Key Features:
- Fires only ONCE per key press (no repeat)
- Good for detecting when user finishes pressing
- Useful for toggle behaviors
- Fires for ALL keys
3. keypress Event (⚠️ DEPRECATED)
The keypress event is deprecated and should NOT be used in new code.
Why is it deprecated?
- It only fires for character-producing keys (not for Shift, Ctrl, arrows, etc.)
- Inconsistent behavior across browsers
event.keyCodevalues were unreliable- Replaced by
keydownwithevent.keyproperty
// ❌ OLD WAY (deprecated)
document.addEventListener('keypress', function(e) {
console.log('keypress:', e.keyCode);
});
// ✅ NEW WAY (recommended)
document.addEventListener('keydown', function(e) {
console.log('keydown:', e.key);
});// When pressing 'a': keydown: a
Key Properties of KeyboardEvent
When a keyboard event fires, the browser creates a KeyboardEvent object that contains many useful properties:
event.key (Recommended ✅)
Returns the value of the key pressed as a string.
| Key Pressed | event.key Value |
|---|---|
| A key | "a" or "A" (with Shift) |
| Enter | "Enter" |
| Space | " " |
| Arrow Up | "ArrowUp" |
| Escape | "Escape" |
| Shift | "Shift" |
| Tab | "Tab" |
event.code (Physical Key)
Returns the physical key on the keyboard, regardless of layout or modifier state.
| Key Pressed | event.code Value |
|---|---|
| A key | "KeyA" (always, even with Shift) |
| 1 key (top row) | "Digit1" |
| 1 key (numpad) | "Numpad1" |
| Left Shift | "ShiftLeft" |
| Right Shift | "ShiftRight" |
| Space | "Space" |
| Enter | "Enter" |
event.keyCode (⚠️ Deprecated)
Returns a numeric code. Do NOT use in new code — use event.key or event.code instead.
Modifier Key Properties
| Property | Description |
|---|---|
event.ctrlKey | true if Ctrl was held |
event.shiftKey | true if Shift was held |
event.altKey | true if Alt was held |
event.metaKey | true if Meta/Command(⌘) was held |
event.repeat
Returns true if the key is being held down and the event is firing repeatedly.
document.addEventListener('keydown', function(e) {
if (e.repeat) {
console.log(`Key "${e.key}" is being held down (repeating)`);
} else {
console.log(`Key "${e.key}" pressed`);
}
});Key "a" pressed Key "a" is being held down (repeating) Key "a" is being held down (repeating) Key "a" is being held down (repeating)
Code Examples
Example 1: Basic keydown Event
// Listen for any key press on the document
document.addEventListener('keydown', function(event) {
console.log('Key pressed:', event.key);
console.log('Code:', event.code);
console.log('Ctrl:', event.ctrlKey);
console.log('Shift:', event.shiftKey);
console.log('Alt:', event.altKey);
console.log('---');
});
// Simulating: User presses 'a', then Shift+BKey pressed: a Code: KeyA Ctrl: false Shift: false Alt: false --- Key pressed: B Code: KeyB Ctrl: false Shift: true Alt: false ---
Example 2: Detecting Enter Key Press
const searchInput = document.getElementById('search');
searchInput.addEventListener('keydown', function(event) {
if (event.key === 'Enter') {
console.log('Enter pressed! Searching for:', this.value);
// Perform search
performSearch(this.value);
}
});
// Alternative: also handle Escape to clear
searchInput.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
this.value = '';
this.blur(); // Remove focus
console.log('Input cleared and blurred');
}
});
// Simulating: User types "javascript" and presses EnterEnter pressed! Searching for: javascript
Example 3: Keyboard Shortcuts (Ctrl+S Save)
Document saved! (Custom save handler)
Example 4: Arrow Key Movement (Game-Style)
Moved RIGHT → Position: (10, 0) Moved RIGHT → Position: (20, 0) Moved DOWN → Position: (20, 10)
Example 5: key vs code Property Difference
document.addEventListener('keydown', function(event) {
console.log(`event.key: "${event.key}" | event.code: "${event.code}"`);
});
// Test 1: Press 'a' without Shift
// Test 2: Press 'A' with Shift held
// Test 3: Press '1' on top row
// Test 4: Press '1' on numpad
// Test 5: Press 'z' on QWERTY layout
// (On AZERTY layout, same physical key would give 'w')// Test 1: Press 'a' without Shift event.key: "a" | event.code: "KeyA" // Test 2: Press 'A' with Shift event.key: "A" | event.code: "KeyA" // Test 3: Press '1' top row event.key: "1" | event.code: "Digit1" // Test 4: Press '1' numpad event.key: "1" | event.code: "Numpad1" // Test 5: Press 'z' on QWERTY (same physical key = 'w' on AZERTY) event.key: "z" | event.code: "KeyZ"
When to use which:
- Use
event.keywhen you care about WHAT character/value the user typed (e.g., form input, text processing) - Use
event.codewhen you care about WHICH physical key was pressed (e.g., game controls like WASD that should work on any keyboard layout)
Example 6: Preventing Default Behavior
Number allowed: 9 Blocked key: a Number allowed: 1 Blocked key: $
Example 7: keydown vs keyup Timing
[1718150400000] keydown: x [1718150400150] keyup: x
Example 8: Detecting Multiple Keys Simultaneously
Keys currently held: Control Keys currently held: Control + Shift Keys currently held: Control + Shift + p 🖨️ Custom Print triggered! Key released: p | Still held: Control + Shift Key released: Shift | Still held: Control Key released: Control | Still held: none
Building a Keyboard Shortcut System
In real-world applications, you need to build a proper keyboard shortcut system. Below is a production-ready implementation:
✅ Registered shortcut: ctrl+s → Save document ✅ Registered shortcut: ctrl+shift+n → New document ✅ Registered shortcut: ctrl+k → Open command palette ✅ Registered shortcut: escape → Close modal/dialog ✅ Registered shortcut: ctrl+z → Undo last action ✅ Registered shortcut: ctrl+shift+z → Redo last action 📋 Registered Shortcuts: ──────────────────────────────────────── ctrl+s │ Save document ctrl+shift+n │ New document ctrl+k │ Open command palette escape │ Close modal/dialog ctrl+z │ Undo last action ctrl+shift+z │ Redo last action ──────────────────────────────────────── 💾 Document saved!
Advanced: Scope-Based Shortcuts
✅ [editor] Registered: ctrl+b → Toggle bold ✅ [editor] Registered: ctrl+i → Toggle italic ✅ [gallery] Registered: ArrowRight → Next image 🔄 Active scope changed to: "editor"
🚫 Common Mistakes
Mistake 1: Using deprecated keypress event
// ❌ WRONG: keypress is deprecated and doesn't fire for all keys
element.addEventListener('keypress', function(e) {
if (e.key === 'Escape') { // Won't fire for Escape!
closeModal();
}
});// ✅ CORRECT: Use keydown instead
element.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeModal();
}
});// With keypress: Escape key press → Nothing happens (event never fires) // With keydown: Escape key press → Modal closes correctly ✅
Mistake 2: Using deprecated keyCode instead of key
// ❌ WRONG: keyCode is deprecated and inconsistent across browsers
document.addEventListener('keydown', function(e) {
if (e.keyCode === 13) { // Magic number!
submitForm();
}
if (e.keyCode === 27) { // What key is 27??
closeDialog();
}
});// ✅ CORRECT: Use event.key with readable string values
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { // Clear and readable
submitForm();
}
if (e.key === 'Escape') { // Self-documenting
closeDialog();
}
});// Both work, but event.key is: // - More readable // - Self-documenting // - Future-proof // - Consistent across keyboards/layouts
Mistake 3: Not checking event.repeat for single-fire actions
// ❌ WRONG: Fires multiple times when key is held
document.addEventListener('keydown', function(e) {
if (e.key === ' ') {
shootBullet(); // Creates dozens of bullets if spacebar held!
}
});// ✅ CORRECT: Check event.repeat to fire only once
document.addEventListener('keydown', function(e) {
if (e.key === ' ' && !e.repeat) {
shootBullet(); // Only one bullet per press
}
});// Without repeat check (holding spacebar 500ms): // shootBullet() called 15 times! 💥💥💥💥💥💥💥💥💥💥💥💥💥💥💥 // With repeat check (holding spacebar 500ms): // shootBullet() called 1 time! 💥
Mistake 4: Forgetting to preventDefault for custom shortcuts
// ❌ WRONG: Browser's default Ctrl+S (save page) still triggers
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 's') {
saveDocument(); // Saves your document...
// BUT browser's "Save As" dialog also appears! 😱
}
});// Without preventDefault: Custom save + browser "Save As" dialog appears // With preventDefault: Only custom save runs, no browser dialog ✅
Mistake 5: Not handling both Ctrl (Windows) and Meta/Cmd (Mac)
// ❌ WRONG: Only works on Windows/Linux, not Mac
document.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 'c') {
copyToClipboard();
}
});// On Windows: Ctrl+C → Works ✅ // On Mac with wrong code: Cmd+C → Doesn't work ❌ // On Mac with correct code: Cmd+C → Works ✅
Mistake 6: Not disabling shortcuts when user is typing in input fields
// ❌ WRONG: Shortcut fires even when user is typing in search box
document.addEventListener('keydown', function(e) {
if (e.key === 'n') {
openNewFile(); // Fires when user types 'n' in any input! 😱
}
});// Without check: Typing "new" in search → opens new file on 'n' key 😱 // With check: Typing "new" in search → types normally ✅ // Pressing 'n' outside inputs → opens new file ✅
Mistake 7: Using key when code is more appropriate (for games)
// ❌ WRONG: Breaks on non-QWERTY keyboard layouts
document.addEventListener('keydown', function(e) {
if (e.key === 'w') moveUp(); // 'w' is 'z' on AZERTY!
if (e.key === 'a') moveLeft(); // 'a' is 'q' on AZERTY!
});// ✅ CORRECT: Use event.code for physical key position
document.addEventListener('keydown', function(e) {
if (e.code === 'KeyW') moveUp(); // Always top-left key
if (e.code === 'KeyA') moveLeft(); // Always left-middle key
if (e.code === 'KeyS') moveDown();
if (e.code === 'KeyD') moveRight();
});// QWERTY user presses 'W' key: // event.key = "w", event.code = "KeyW" → moveUp() ✅ // AZERTY user presses same physical key (labeled 'Z'): // event.key = "z", event.code = "KeyW" → moveUp() ✅ (with code) // event.key = "z" ≠ "w" → nothing happens ❌ (with key)
🎯 Key Takeaways
- Use
keydownfor most cases – It fires for all keys and supportspreventDefault(). Avoid deprecatedkeypress.
- Use
event.keyfor character detection – It returns a human-readable string like"Enter","a","ArrowUp". Much better than numerickeyCode.
- Use
event.codefor physical keys – When building games or keyboard shortcuts that should work regardless of keyboard layout (QWERTY, AZERTY, DVORAK).
- Always call
event.preventDefault()when overriding browser shortcuts like Ctrl+S, Ctrl+P, etc.
- Handle both
ctrlKeyandmetaKey– This ensures your shortcuts work on both Windows/Linux (Ctrl) and Mac (Cmd/⌘).
- Check
event.repeatfor actions that should fire only once per keypress (shooting, toggling, submitting forms).
- Disable shortcuts in input fields – Always check if
event.targetis an INPUT, TEXTAREA, or contentEditable element before triggering single-key shortcuts.
keydownfires repeatedly when held;keyupfires only once on release. Usekeyupfor toggle states and final actions.
- Clean up event listeners – Always remove keyboard listeners when components unmount or modals close to prevent memory leaks.
- Build a shortcut system – For complex applications, create a centralized keyboard shortcut manager instead of scattered event listeners.
❓ Interview Questions
Q1: What is the difference between keydown, keypress, and keyup events?
Answer:
keydown: Fires when a key is pressed down. Works for ALL keys (character + non-character). Fires repeatedly when held. This is the recommended event for most use cases.keypress: ⚠️ DEPRECATED. Used to fire only for character-producing keys (not Shift, Ctrl, arrows). Had inconsistent behavior across browsers. Do not use in new code.keyup: Fires when a key is released. Fires only ONCE regardless of how long the key was held. Good for detecting end of key press.
Event order: keydown → keypress (deprecated) → input updates → keyup
Q2: What is the difference between event.key and event.code?
Answer:
event.key: Returns the logical value of the key. It's affected by modifier keys and keyboard layout. Pressing 'a' gives"a", pressing Shift+'a' gives"A".event.code: Returns the physical key identifier. It's NOT affected by modifiers or layout. The 'A' key always returns"KeyA"whether Shift is held or not, and regardless of whether the keyboard is QWERTY or AZERTY.
Use key when you care about the character (form input, text editor). Use code when you care about the physical position (game controls, WASD movement).
Q3: How would you implement a keyboard shortcut like Ctrl+Shift+P that works on both Windows and Mac?
Answer:
Key points:
- Check both
ctrlKeyandmetaKeyfor cross-platform support - Always
preventDefault()to stop browser default actions - Compare
event.keyto'P'(uppercase because Shift is held)
Q4: Why is event.keyCode deprecated? What should be used instead?
Answer: event.keyCode is deprecated because:
- It returns numeric codes that are hard to read/maintain
- Values are inconsistent across different browsers
- Different keys can produce the same keyCode in different contexts
- It doesn't properly handle international keyboard layouts
Use instead:
event.key– returns readable strings like"Enter","a","ArrowUp"event.code– returns physical key identifiers like"KeyA","Digit1","Space"
Q5: How do you detect if a key is being held down (auto-repeating)?
Answer:
document.addEventListener('keydown', function(event) {
if (event.repeat) {
console.log('Key is being held down (repeat)');
return; // Skip if you only want first press
}
console.log('Initial key press');
});The event.repeat property is true when the event is firing due to auto-repeat (key held down). It's false for the initial press. This is important for:
- Games (shoot once per press, not continuously)
- Form submissions (prevent multiple submits)
- Toggle actions (toggle once, not flicker)
Q6: What happens if you add a keyboard event listener to a <div> element?
Answer: By default, a <div> element cannot receive keyboard events because it's not focusable. Keyboard events only fire on elements that have focus.
To make a <div> receive keyboard events:
// Option 1: Add tabindex attribute
const div = document.querySelector('#my-div');
div.setAttribute('tabindex', '0'); // Makes it focusable
div.addEventListener('keydown', function(e) {
console.log('Key pressed on div:', e.key);
});
// Option 2: Listen on document (catches all keyboard events)
document.addEventListener('keydown', function(e) {
console.log('Key pressed anywhere:', e.key);
});tabindex="0" makes the element focusable via Tab key and click. tabindex="-1" makes it focusable only programmatically (via .focus()).
Q7: How would you prevent a user from typing non-numeric characters in an input field using keyboard events?
Answer:
Note: For production, also use the input event as a fallback (handles paste, drag-drop, autofill) and the pattern attribute for HTML validation.
📝 FAQ
Q: Should I use keydown or keyup for form submission?
A: Use keydown for form submission (Enter key detection). It fires before the input value updates and allows you to call preventDefault() to stop any default form submission. keyup is too late — by the time it fires, the form may already have been submitted.
form.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
validateAndSubmit();
}
});Q: Can I detect which specific Shift key (left or right) was pressed?
A: Yes! Use event.code which differentiates between left and right modifier keys:
document.addEventListener('keydown', function(e) {
if (e.code === 'ShiftLeft') console.log('Left Shift pressed');
if (e.code === 'ShiftRight') console.log('Right Shift pressed');
if (e.code === 'ControlLeft') console.log('Left Ctrl pressed');
if (e.code === 'ControlRight') console.log('Right Ctrl pressed');
});Note: event.key just returns "Shift" for both, while event.code gives "ShiftLeft" or "ShiftRight".
Q: Do keyboard events bubble? Can I use event delegation?
A: Yes! Keyboard events bubble up through the DOM just like click events. You can use event delegation:
This is more efficient than attaching individual listeners to each input element.
Q: What is the difference between keyboard events on <input> and on document?
A:
- On
document: Catches ALL keyboard events regardless of which element has focus. Good for global shortcuts, game controls, and accessibility features. - On
<input>: Only fires when that specific input has focus. Good for field-level validation, auto-complete triggers, and input-specific behavior.
// Global: fires regardless of focus
document.addEventListener('keydown', globalHandler);
// Local: fires only when this input is focused
myInput.addEventListener('keydown', localHandler);If both are registered and the input has focus, BOTH fire (local first due to bubbling, then global — unless stopPropagation() is called).
Q: How do I handle keyboard events in React / modern frameworks?
A: In React, use the synthetic onKeyDown event:
Key differences in React:
- Events are camelCase:
onKeyDown, notonkeydown - React uses SyntheticEvent (wraps native event)
- Use
useEffectcleanup to remove global listeners onKeyPressis deprecated in React too — useonKeyDown
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Keyboard Events – Complete Guide to keydown, keyup & Key Properties (2026).
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, events, keyboard, javascript keyboard events – complete guide to keydown, keyup & key properties (2026)
Related JavaScript Master Course Topics