Справочник · JavaScript
keydown и keyup: реагируем на клавиатуру
Событие keydown срабатывает при нажатии клавиши, keyup — при её отпускании. В объекте события event.key содержит символ или название клавиши с учётом раскладки ('a', 'ф', 'Enter', 'Escape'), а event.code — физическую клавишу независимо от раскладки ('KeyA'). Так делают горячие клавиши и закрытие окон по Escape.
keydown— нажали (повторяется при удержании),keyup— отпустили.event.key— что напечаталось,event.code— какая клавиша нажата.- Горячие клавиши проверяй через
event.code, иначе они не сработают на русской раскладке. - Модификаторы:
ctrlKey,metaKey(Cmd),shiftKey,altKey. keypressиkeyCodeустарели — не используй их.
Минимальный пример: закрыть окно по Escape
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
closeModal();
}
});Обработчик висит на document, поэтому ловит нажатия, где бы ни был фокус. Escape — привычный способ закрыть меню, подсказку или модальное окно. Тег dialog, открытый через showModal(), закрывается по Escape сам.
event.key или event.code
| Нажатие | event.key | event.code |
|---|---|---|
| A на английской раскладке | 'a' | 'KeyA' |
| Та же клавиша на русской | 'ф' | 'KeyA' |
| Shift + A | 'A' | 'KeyA' |
| Пробел | ' ' | 'Space' |
| Enter | 'Enter' | 'Enter' или 'NumpadEnter' |
| Стрелка вверх | 'ArrowUp' | 'ArrowUp' |
| Цифра 1 над буквами | '1' | 'Digit1' |
key — смысл нажатия: какой символ напечатан или какая это служебная клавиша. Подходит для Escape, Enter, стрелок и проверки введённого символа. code — место клавиши на клавиатуре. Подходит для горячих клавиш и игр: Ctrl+K должно работать и тогда, когда у человека включена русская раскладка.
Горячие клавиши с Ctrl и Cmd
document.addEventListener('keydown', (event) => {
const mod = event.ctrlKey || event.metaKey; // Ctrl в Windows, Cmd в macOS
if (mod && event.code === 'KeyK') {
event.preventDefault(); // не открывать поиск браузера
document.querySelector('#site-search').focus();
}
});В macOS привычные сочетания используют Cmd (metaKey), а в Windows и Linux — Ctrl (ctrlKey), поэтому проверяют оба. preventDefault() отменяет действие браузера по умолчанию для этого сочетания. Не перехватывай системные сочетания вроде Ctrl+C, Ctrl+V и Ctrl+F без серьёзной причины — люди ждут от них привычного поведения.
Не мешай вводу текста
document.addEventListener('keydown', (event) => {
const target = event.target;
const isTyping = target.closest('input, textarea, select, [contenteditable="true"]');
if (isTyping || event.isComposing) return; // человек печатает — не перехватываем
if (event.key === '/') {
event.preventDefault();
document.querySelector('#site-search').focus();
}
});Однобуквенные горячие клавиши вроде «/» для поиска не должны срабатывать, когда человек печатает в поле. Проверяй, где фокус, и пропускай событие. event.isComposing равен true, пока идёт ввод через методы ввода для китайского, японского и других языков — в это время нажатия тоже нельзя перехватывать.
Enter в полях и кнопках
// Enter в поле поиска — запуск без формы
searchInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') runSearch(searchInput.value);
});
// Ctrl+Enter — отправить комментарий из textarea
comment.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) form.requestSubmit();
});Если поле стоит внутри form, Enter отправит форму сам — достаточно слушать событие submit. Для кнопок не нужно ловить Enter и пробел вручную: button превращает их в click автоматически. Ручная обработка клавиш нужна, только если элемент нестандартный.
Удержание клавиши и keyup
document.addEventListener('keydown', (event) => {
if (event.repeat) return; // игнорировать автоповтор при удержании
if (event.code === 'Space') startCharging();
});
document.addEventListener('keyup', (event) => {
if (event.code === 'Space') release();
});При удержании клавиши keydown приходит снова и снова с event.repeat === true. Если действие должно случиться один раз, проверяй этот флаг. keyup нужен, когда важен момент отпускания: игры, «нажми и держи».
Свойства события клавиатуры
| Свойство | Что даёт |
|---|---|
key | символ или название клавиши с учётом раскладки |
code | физическая клавиша |
ctrlKey, metaKey, shiftKey, altKey | зажаты ли модификаторы |
repeat | автоповтор при удержании |
isComposing | идёт составной ввод (IME) |
keyCode, which | устарели, не используй |
keydown или keyup
Реакция сразу при нажатии, можно отменить действие браузера через preventDefault. Для горячих клавиш, Escape и навигации стрелками.
Срабатывает при отпускании, один раз. Для действий «по окончании» нажатия и игр.
Частые ошибки
- Проверяют горячие клавиши через
event.key === 'k', и на русской раскладке они не работают. - Используют устаревшие
keypressиkeyCode. - Перехватывают однобуквенные клавиши, пока человек печатает в поле.
- Ловят Enter на кнопке вручную, хотя button сам превращает его в click.
- Отменяют привычные сочетания браузера (Ctrl+F, Ctrl+C) без необходимости.
Доступность
Клавиатура — основной способ работы для многих людей, поэтому всё, что делается мышью, должно делаться и с клавиатуры. Однобуквенные горячие клавиши по требованиям WCAG должны отключаться или срабатывать только при фокусе на элементе: иначе они мешают голосовому вводу и скринридерам, у которых свои сочетания. Не перехватывай клавиши, которые используют скринридеры, и показывай подсказку о доступных сочетаниях.
Поддержка браузерами
keydown, keyup, event.key, event.code, repeat и isComposing поддерживаются всеми актуальными браузерами. На телефонах с экранной клавиатурой события клавиатуры приходят не всегда предсказуемо — для полей ввода надёжнее событие input.
Практика
Сделай три вещи: по Escape закрывай открытое меню (атрибут hidden), по «/» переводи фокус в поле поиска, но только если человек сейчас не печатает в другом поле, а по Ctrl+K или Cmd+K тоже открывай поиск — на любой раскладке.
Показать решение
const menu = document.querySelector('#menu');
const search = document.querySelector('#site-search');
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !menu.hidden) {
menu.hidden = true;
return;
}
if ((event.ctrlKey || event.metaKey) && event.code === 'KeyK') {
event.preventDefault();
search.focus();
return;
}
const typing = event.target.closest('input, textarea, select, [contenteditable="true"]');
if (!typing && !event.isComposing && event.key === '/') {
event.preventDefault();
search.focus();
}
});Частые вопросы
Чем event.key отличается от event.code?
key — символ или название клавиши с учётом раскладки и Shift ('a', 'ф', 'A', 'Enter'). code — физическая клавиша независимо от раскладки ('KeyA').
Почему горячая клавиша не работает на русской раскладке?
Она проверяется через event.key, а на русской раскладке клавиша K даёт 'л'. Проверяй event.code === 'KeyK'.
Почему keydown срабатывает много раз?
При удержании клавиши браузер повторяет событие. Пропускай повторы проверкой event.repeat.
Что использовать вместо keypress и keyCode?
Событие keydown и свойства event.key или event.code. keypress и keyCode устарели.
Как отменить действие браузера для сочетания клавиш?
Вызови event.preventDefault() в обработчике keydown. Но не перехватывай привычные системные сочетания без серьёзной причины.