Skip to content

Keyboard Events — Complete Guide

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you will learn about Keyboard Events. We cover key concepts, practical examples, and best practices to help you master this topic.

Keyboard events (keydown, keyup, keypress) enable JavaScript to respond to key presses for shortcuts, game controls, navigation, and form input handling.

What You'll Learn

  • The difference between keydown, keyup, and keypress events
  • How to read which key was pressed using event.key, event.code, and event.keyCode
  • How to detect modifier keys (Ctrl, Shift, Alt, Meta)
  • How to implement keyboard shortcuts and navigation

Why It Matters

Keyboard support is essential for Accessibility, power users, and applications that need fast input. Games, text editors, spreadsheets, and productivity tools all depend on precise keyboard event handling.

Real-World Use

  • A code editor uses keyboard shortcuts for save, find, and format
  • A game uses WASD keys for player movement
  • A spreadsheet handles arrow keys for cell navigation
  • A modal closes on Escape key press
flowchart LR
  A[Key Pressed] --> B[keydown]
  B --> C[Check event.key]
  C --> D{Which key?}
  D -->|Arrow| E[Navigate]
  D -->|Enter| F[Submit]
  D -->|Escape| G[Close modal]
  D -->|Ctrl+S| H[Save]
  B --> I[keyup]
  I --> J[Key released]

Keydown, Keyup, and Keypress

The three keyboard events fire in sequence when a key is pressed.

const input = document.querySelector('.key-demo');

// keydown: fires when key is first pressed (repeats while held)
input.addEventListener('keydown', function(event) {
    console.log('keydown:', {
        key: event.key,
        code: event.code,
        repeat: event.repeat
    });

    // Detect held key (auto-repeat)
    if (event.repeat) {
        console.log('Key is being held down');
    }
});

// keypress: DEPRECATED — do not use
// It had inconsistent behavior across browsers

// keyup: fires when key is released
input.addEventListener('keyup', function(event) {
    console.log('keyup:', event.key);
    console.log('Key released after', 
        event.timeStamp - this._lastKeydown || 0, 'ms');
});

input._lastKeydown = 0;
input.addEventListener('keydown', function() {
    this._lastKeydown = event.timeStamp;
});

Expected output: Pressing and releasing a key shows keydown (possibly multiple times with repeat:true) followed by keyup. The keypress event is not used.

event.key vs event.code vs event.keyCode

Each property tells you something different about the pressed key.

document.addEventListener('keydown', function(event) {
    // event.key: the actual character or key name
    console.log('event.key:', event.key);

    // event.code: the physical key position (in)
    console.log('event.code:', event.code);

    // event.keyCode: DEPRECATED numeric code
    // console.log('event.keyCode:', event.keyCode);

    // Examples:
    // Pressing 'a' gives: key="a", code="KeyA"
    // Pressing 'A' gives: key="A", code="KeyA"
    // Pressing '1' gives: key="1", code="Digit1"
    // Pressing '!' gives: key="!", code="Digit1"
    // Pressing Enter gives: key="Enter", code="Enter"
    // Pressing ArrowUp gives: key="ArrowUp", code="ArrowUp"

    // Use event.key for character meaning
    // Use event.code for physical key position
});

Expected output: Pressing different keys shows different key and code values. The same physical key with Shift produces different event.key but the same event.code.

Detecting Modifier Keys

Check ctrlKey, shiftKey, altKey, and metaKey properties for combinations.

document.addEventListener('keydown', function(event) {
    const modifiers = {
        ctrl: event.ctrlKey,
        shift: event.shiftKey,
        alt: event.altKey,
        meta: event.metaKey    // Command key on Mac, Windows key on PC
    };

    // Ctrl+S (Save)
    if (event.ctrlKey && event.key === 's') {
        event.preventDefault();
        console.log('Save shortcut triggered');
        saveDocument();
    }

    // Ctrl+Shift+N (New incognito-style)
    if (event.ctrlKey && event.shiftKey && event.key === 'N') {
        event.preventDefault();
        console.log('Ctrl+Shift+N pressed');
        openNewPrivateWindow();
    }

    // Alt+D (Focus address bar equivalent)
    if (event.altKey && event.key === 'd') {
        event.preventDefault();
        console.log('Alt+D pressed');
        focusSearchBar();
    }

    // Escape (cancel/close)
    if (event.key === 'Escape') {
        console.log('Escape pressed');
        closeModal();
        blurActiveElement();
    }

    console.log('Modifiers:', modifiers);
});

Expected output: Pressing key combinations triggers the corresponding shortcuts. The browser's default behavior (like Ctrl+S opening save dialog) is prevented.

Arrow Keys and Navigation

Arrow keys, Home, End, PageUp, and PageDown are commonly used for navigation.

const itemList = document.querySelector('.item-list');
const items = itemList.querySelectorAll('.item');

let currentIndex = 0;

itemList.addEventListener('keydown', function(event) {
    const items = this.querySelectorAll('.item');
    let newIndex = currentIndex;

    switch (event.key) {
        case 'ArrowDown':
            event.preventDefault();
            newIndex = Math.min(currentIndex + 1, items.length - 1);
            break;
        case 'ArrowUp':
            event.preventDefault();
            newIndex = Math.max(currentIndex - 1, 0);
            break;
        case 'Home':
            event.preventDefault();
            newIndex = 0;
            break;
        case 'End':
            event.preventDefault();
            newIndex = items.length - 1;
            break;
        case 'Enter':
        case ' ':
            event.preventDefault();
            items[currentIndex]?.click();
            return;
        default:
            return; // Ignore other keys
    }

    if (newIndex !== currentIndex) {
        items[currentIndex]?.classList.remove('focused');
        items[newIndex]?.classList.add('focused');
        items[newIndex]?.focus();
        currentIndex = newIndex;
        console.log('Selected item:', newIndex);
    }
});

// Ensure items are focusable
items.forEach(item => item.setAttribute('tabindex', '-1'));
itemList.setAttribute('tabindex', '0');

Expected output: When the list has focus, arrow keys move the selected item up and down. Home and End jump to the first and last items. Enter activates the selected item.

Debouncing Keyboard Input

For search-as-you-type functionality, debounce the input handler.

const searchBox = document.querySelector('#search-input');
let debounceTimer;

searchBox.addEventListener('input', function(event) {
    // Clear previous timer
    clearTimeout(debounceTimer);

    const query = this.value.trim();
    console.log('User typed:', query);

    // Set new timer — wait 300ms after last keystroke
    debounceTimer = setTimeout(() => {
        if (query.length >= 2) {
            console.log('Searching for:', query);
            performSearch(query);
        }
    }, 300);
});

// Without debounce: every keystroke triggers a search
// With debounce: only triggers 300ms after the user stops typing

async function performSearch(query) {
    console.log('API call for:', query);
    // const results = await fetch(`/api/search?q=${query}`);
    // renderResults(results);
}

Expected output: As the user types rapidly, the search function is not called until they pause for 300ms. This reduces API calls and improves performance.

Preventing Default Keyboard Behavior

Some keys have browser defaults that interfere with applications.

const editableDiv = document.querySelector('.custom-editor');

editableDiv.addEventListener('keydown', function(event) {
    // Prevent Tab from leaving the editor
    if (event.key === 'Tab') {
        event.preventDefault();
        // Insert spaces or a tab character
        document.execCommand('insertHTML', false, '    ');
    }

    // Prevent back navigation on Backspace
    if (event.key === 'Backspace' && !this.textContent.length) {
        event.preventDefault();
    }

    // Custom handling for Ctrl+B (bold)
    if (event.ctrlKey && event.key === 'b') {
        event.preventDefault();
        document.execCommand('bold', false);
        console.log('Toggled bold');
    }

    // Prevent page scroll on arrow keys
    if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
        event.preventDefault();
        // Custom cursor movement logic
    }
});

// Always provide user feedback when preventing default
// Show a message or visual indicator of what happened

Expected output: Tab inserts spaces instead of leaving the editor. Arrow keys do not scroll the page. Backspace on empty content does not navigate back. Ctrl+B toggles bold formatting.

Common Mistakes

  1. Using keypress instead of keydown — keypress is deprecated and does not fire for non-character keys (arrows, Escape, function keys). Use keydown or keyup.
  2. Not preventing default for shortcuts — If you handle Ctrl+S, call event.preventDefault() to prevent the browser's save dialog from appearing.
  3. Using event.keyCode (deprecated) — keyCode is deprecated and may not work in future browsers. Use event.key or event.code instead.
  4. Forgetting to handle keyboard events on non-input elements — Non-focusable elements (div, span) do not receive keyboard events. Add tabindex to make them focusable.
  5. Not checking event.repeat — When a key is held, keydown fires repeatedly with repeat:true. Some handlers should ignore repeated events (like navigation).

Practice Questions

  1. What is the difference between event.key and event.code? event.key returns the character or key name (affected by Shift/CapsLock). event.code returns the physical key position (unaffected by modifiers).
  2. Why is event.keyCode deprecated? It was inconsistent across browsers (different values for the same key), and the standard now recommends event.key and event.code.
  3. How do you detect Ctrl+C? Check event.ctrlKey && event.key === 'c'. Prevent default if you want to intercept the copy action.
  4. Challenge: Implement keyboard shortcut hints. When the user presses the Ctrl key, show tooltips next to buttons indicating their keyboard shortcuts (like "Ctrl+S" next to Save). Hide tooltips when Ctrl is released.

FAQ

Does keydown repeat when a key is held?

Yes. keydown fires repeatedly while the key is held. Check event.repeat to distinguish initial press from repeats.

Can I detect the physical keyboard layout?

No. The browser does not expose keyboard layout. event.code gives the physical key position regardless of layout.

Why does event.key return 'Dead' for some keys?

Dead keys (like accent keys on some keyboards) wait for the next key to produce a combined character. event.key is 'Dead' during the wait.

How do I handle international keyboard input?

Use the input event for text entry (handles IME composition correctly). Use keyboard events only for shortcuts and navigation.

Do keyboard events work on mobile devices?

Partially. Mobile keyboards trigger input events but may not trigger keydown for all keys (like emoji or predictive text selections).

Mini Project

Build a keyboard shortcut help overlay. Pressing Ctrl+/ (or ?) shows a modal with all available keyboard shortcuts grouped by category. The shortcuts should include: Ctrl+S (save), Ctrl+Z (undo), Ctrl+Shift+Z (redo), Ctrl+F (find), Escape (close), Arrow keys (navigation). Each shortcut should show the key combination and a description. Close the overlay with Escape or clicking outside.

What's Next

Continue with Lesson 18: Mouse Events to learn about mouse-specific events like click, dblclick, mousedown, mouseup, mousemove, and contextmenu.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro