keydown on document, modifier keys & focus
Keyboard shortcuts
Lesson 18 of 20 · 12 min · Module 5: Smoother interactions
Shortcuts make frequent actions fast: / to search on many sites, j and k to move through a list. Done carelessly, they also hijack typing and clash with the browser’s own keys.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Handle page-wide keys with a keydown listener on document
- Keep shortcuts away from typing and browser shortcuts
- Prevent the default only for keys you handle
The idea
Listen for keydown on document and check event.key. Ignore keys typed into text fields, which you can detect with event.target.closest('input, textarea'), and keys pressed together with Ctrl, ⌘ or Alt, which belong to the browser and the system. Call event.preventDefault() only for the keys you actually handle.
document.addEventListener('keydown', event => {
if (event.key === '?' && !event.target.closest('input, textarea')) {
console.log('Show the list of shortcuts');
}
});
01Listen on the whole document
Key events start at the focused element, or at the body when nothing is focused, and bubble up to document. One listener there sees every key press on the page, which is exactly what page-wide shortcuts need.
02Shortcuts must not steal typing
If j moved the highlight while someone typed “javascript” into the search box, the box would be unusable. Checking event.target first, and skipping text fields, solves it. Escape is the useful exception: it lets people leave the box without the mouse.
const typing = event.target.closest('input, textarea, select, [contenteditable]');
if (typing) return;
03Leave the system alone
Ctrl + F, ⌘ + L and Alt + ← belong to the browser and the operating system, so return early when a modifier is pressed. Document your shortcuts on the page, and offer a way to turn single-key shortcuts off: accessibility guidelines ask for it, because people using speech input can trigger them by accident.
Your turn
keydown listener on document: 1) do nothing when ctrlKey, metaKey or altKey is set; 2) Escape in #search clears it and leaves it with blur(); 3) leave every other key typed in a text field alone; 4) / prevents the default and focuses #search; 5) j and k move the highlight to the next and the previous lesson, stopping at the first and the last one, and call render().What the checks look for
- The first lesson starts highlighted
- / jumps to the search box
- j and k move the highlight
- The highlight stops at both ends
- Typing in the search box is never a shortcut
- Escape clears and leaves the search box
- Ctrl, ⌘ and Alt combinations are left to the browser
Take this with you
Check modifiers and focus first, then handle only the keys you own.
Go a little further
Add ? to show and hide a list of the shortcuts, and a checkbox that turns the single-key shortcuts off.