События focus и blur в JavaScript
Узнайте, как работают события focus и blur в JavaScript, чем они отличаются от focusin и focusout, и как применять их для валидации форм и управления фокусом.
JavaScript даёт вам точный контроль над тем, какой элемент в данный момент сфокусирован — то есть получает ввод с клавиатуры. События focus и blur позволяют реагировать в тот момент, когда элемент получает или теряет фокус, что является основой встроенной валидации форм, подсветки активного поля, создания виджетов с поддержкой клавиатуры и навигации пользователя по форме. В этой статье рассматриваются сами события, их отличия от «всплывающих» аналогов focusin/focusout, а также несколько практических паттернов.
Эта страница основана на введении в браузерные события. Если вам нужно обрабатывать события сразу на множестве элементов, также прочитайте о всплытии и перехвате событий.
Что такое focus и blur в JavaScript
Событие focus срабатывает, когда элемент становится активной целью ввода с клавиатуры — тем элементом, на который указывает document.activeElement. Событие blur срабатывает, когда этот элемент теряет фокус, например, когда пользователь щёлкает в другом месте, нажимает Tab или фокус перемещается программно.
По умолчанию фокусируются только интерактивные элементы: ссылки (<a href>), элементы управления форм (<input>, <textarea>, <select>, <button>) и ещё несколько других. Чтобы сделать фокусируемым любой элемент — <div>, <span> или <li> — добавьте ему атрибут tabindex. Используйте tabindex="0", чтобы включить элемент в естественный порядок табуляции, или tabindex="-1", чтобы элемент был фокусируемым только программно (element.focus()).
Важный нюанс: focus и blur не всплывают. Обработчик, прикреплённый к родительскому элементу, не сработает, когда дочерний input получит фокус. Когда вам нужна делегация событий на контейнере, используйте всплывающие аналоги focusin и focusout — они работают идентично, но распространяются вверх по дереву DOM.
focus vs. blur vs. focusin vs. focusout
| Событие | Срабатывает когда | Всплывает? |
|---|---|---|
focus | элемент получает фокус | Нет |
blur | элемент теряет фокус | Нет |
focusin | элемент получает фокус | Да |
focusout | элемент теряет фокус | Да |
Для одного конкретного элемента проще всего использовать focus/blur. Для целой формы или списка полей — прикрепите focusin/focusout один раз к контейнеру.
Как реализовать обработку события focus
Чтобы использовать событие focus, прикрепите обработчик к элементу. Пример ниже подсвечивает input в момент, когда он получает фокус:
<input type="text" id="nameInput" placeholder="Enter Your Name">
<script>
document.getElementById('nameInput').addEventListener('focus', function(event) {
event.target.style.backgroundColor = 'lightblue';
});
</script>Этот фрагмент кода делает фон поля ввода светло-голубым, когда оно сфокусировано, улучшая пользовательский интерфейс и показывая, где пользователь сейчас печатает. Для простой стилизации рассмотрите использование CSS-псевдокласса `:focus` как стандартной альтернативы без JavaScript:
input:focus {
background-color: lightblue;
}Как реализовать обработку события blur
Валидация по событию blur — одно из наиболее распространённых применений этих событий: вы позволяете пользователю закончить ввод, а затем проверяете значение, когда он переходит к другому полю. Вот как проверить адрес электронной почты, когда input теряет фокус:
<input type="email" id="emailInput" placeholder="Enter Your Email">
<script>
document.getElementById('emailInput').addEventListener('blur', function(event) {
// Simplified regex for educational purposes
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(event.target.value)) {
alert('Please enter a valid email address.');
event.target.style.backgroundColor = 'salmon';
} else {
event.target.style.backgroundColor = 'lightgreen';
}
});
</script>Этот скрипт проверяет, соответствует ли введённый email стандартному формату, и уведомляет пользователя, если ввод некорректен. Фон меняется на зелёный при корректном значении и на лососёвый — при некорректном, обеспечивая мгновенную визуальную обратную связь.
Программное управление фокусом
Помимо реакции на события, вы можете перемещать фокус самостоятельно с помощью element.focus() и снимать его с помощью element.blur(). Это полезно, чтобы поместить курсор в первое поле при загрузке страницы или вернуть фокус к некорректному полю после валидации.
<input id="search" placeholder="Search..." />
<button id="go">Focus the search box</button>
<script>
document.getElementById('go').addEventListener('click', () => {
document.getElementById('search').focus();
});
</script>Два полезных дополнения:
document.activeElementвсегда возвращает элемент, который в данный момент имеет фокус (или<body>, если такого нет). Удобно для проверки состояния фокуса без обработчиков событий.focus({ preventScroll: true })фокусирует элемент без прокрутки к нему — полезно, когда вы управляете прокруткой самостоятельно.
Для поля, которое должно получать фокус сразу при загрузке страницы, HTML-атрибут autofocus (<input autofocus>) является декларативным вариантом без JavaScript.
Использование focusin/focusout для делегации событий
Поскольку focus и blur не всплывают, прикрепление одного обработчика к форме не позволит перехватить изменения фокуса на её полях. Всплывающие события focusin/focusout решают эту проблему — вы обрабатываете каждое поле из единственного обработчика на родительском элементе:
<form id="signup">
<input name="email" placeholder="Email" />
<input name="password" type="password" placeholder="Password" />
</form>
<script>
const form = document.getElementById('signup');
form.addEventListener('focusin', (event) => {
event.target.style.outline = '2px solid royalblue';
});
form.addEventListener('focusout', (event) => {
event.target.style.outline = '';
});
</script>Событие focusout также предоставляет доступ к event.relatedTarget — элементу, который получит фокус следующим, — что позволяет отследить, куда переходит фокус.
Продвинутые техники: управление несколькими полями
Когда пользователь правильно заполняет поле формы, можно автоматически переместить фокус на следующее поле после выхода из текущего. Это упрощает заполнение формы, устраняя необходимость в ручных кликах. Вот как реализовать это поведение:
<input type="text" id="firstName" placeholder="First Name" />
<input type="text" id="lastName" placeholder="Last Name" />
<div id="error" style="color: red;"></div> <!-- Display error message here -->
<script>
document.getElementById('firstName').addEventListener('blur', validateFirstName);
function validateFirstName(event) {
const input = event.target;
const errorDiv = document.getElementById('error');
// Allow only letters and spaces, must not be empty
const nameRegex = /^[A-Za-z ]+$/;
if (!nameRegex.test(input.value)) {
errorDiv.textContent = 'Please enter a valid first name.'; // Display error message
input.style.backgroundColor = 'salmon'; // Set background to salmon on invalid input
input.focus(); // Keep focus on the first name input to encourage correction
} else {
input.style.backgroundColor = 'white'; // Reset background to white on valid input
errorDiv.textContent = ''; // Clear error message
document.getElementById('lastName').focus(); // Optionally move focus to the last name input
}
}
</script>В этом примере фокус автоматически переходит на поле lastName, как только введено корректное имя, что улучшает пользовательский опыт, сокращая необходимость в ручных кликах.
Вызов
input.focus()из обработчикаblurможет противоречить действиям пользователя. Если пользователь пытался кликнуть на другой элемент, принудительный возврат фокуса может ощущаться как ловушка. Используйте этот паттерн осторожно, предпочитая отображение сообщения об ошибке, которое пользователь сможет исправить в удобном темпе.
Типичные ошибки
- Не ожидайте, что
focus/blurбудут всплывать. Обработчик на контейнере дляfocusникогда не сработает; переключитесь наfocusin/focusoutдля делегации. blurсрабатывает до завершения клика на другом элементе управления. Если обработчикblurскрывает или удаляет элемент, на который пользователь только что кликнул, клик может не зарегистрироваться — сначала проверьтеevent.relatedTarget.- Скрытые элементы или элементы с
display:noneне могут получить фокус. Вызовelement.focus()на них молча ничего не делает. - Принудительная установка фокуса снижает доступность, когда это неожиданно для пользователя. Сохраняйте предсказуемый порядок табуляции и не создавайте ловушек фокуса.
- Для чисто визуальной стилизации фокуса предпочтите CSS-псевдоклассы
:focus/:focus-visibleвместо JavaScript — они не требуют обработчиков и корректно работают при навигации только с клавиатуры.
Заключение
События focus и blur — основа интерактивных и доступных форм. Знание того, что focus/blur не всплывают (а focusin/focusout — всплывают), как перемещать фокус с помощью element.focus() и где провести границу между JavaScript и CSS-псевдоклассом :focus, позволяет создавать отзывчивые элементы ввода, не удивляя пользователей.
Далее изучите связанные браузерные взаимодействия: события клавиатуры, события change, input, cut, copy, paste и всплытие и перехват для делегации событий.