</> Praktum

Главная / JavaScript / keydown и keyup

Справочник · JavaScript

keydown и keyup: реагируем на клавиатуру

Редакция PraktumОбновлено 6 мин чтенияУровень: новичок

Событие 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.keyevent.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 нужен, когда важен момент отпускания: игры, «нажми и держи».

Свойства события клавиатуры

KeyboardEvent
СвойствоЧто даёт
keyсимвол или название клавиши с учётом раскладки
codeфизическая клавиша
ctrlKey, metaKey, shiftKey, altKeyзажаты ли модификаторы
repeatавтоповтор при удержании
isComposingидёт составной ввод (IME)
keyCode, whichустарели, не используй

keydown или keyup

keydown

Реакция сразу при нажатии, можно отменить действие браузера через preventDefault. Для горячих клавиш, Escape и навигации стрелками.

keyup

Срабатывает при отпускании, один раз. Для действий «по окончании» нажатия и игр.

Частые ошибки

  • Проверяют горячие клавиши через 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. Но не перехватывай привычные системные сочетания без серьёзной причины.

Источники

Ещё в разделе JavaScript