Отличный вопрос! Он затрагивает как базовые принципы работы с DOM, так и важные концепции доступности (accessibility). Сфокусироваться на <div> элементарно, но сделать это правильно и семантично — задача для вдумчивого разработчика.
По умолчанию <div> (как и многие другие элементы, например <span>) не является фокусируемым элементом. Это логично, так как <div> — блочный контейнер без семантической нагрузки, и пользователям вспомогательных технологий (скринридеров) обычно не нужно фокусироваться на таких элементах.
Однако в современных SPA и сложных UI-виджетах (кастомные выпадающие списки, модальные окна, деревянные компоненты) часто возникает необходимость программно управлять фокусом именно на контейнерах. Вот как это можно сделать.
1. Основной способ: добавление атрибута tabindex
Ключ к управлению фокусом — глобальный атрибут tabindex.
tabindex="-1": Элемент становится фокусируемым только программно (через JavaScript). Он не будет включен в естественную последовательность табуляции страницы (порядок, в котором элементы получают фокус при нажатии Tab). Это самый частый и правильный случай для <div>.
tabindex="0": Элемент становится фокусируемым и программно, и с клавиатуры (Tab/Shift+Tab). Он включается в естественную последовательность табуляции в том порядке, в котором появляется в DOM. Используйте это с большой осторожностью для <div>!
tabindex="1" и больше: Крайне не рекомендуется. Элемент получает приоритет в табуляции, что ломает ожидаемый пользователем порядок и создает проблемы с доступностью.
Пример:
<div id="myCustomWidget" tabindex="-1">
<p>Контент кастомного виджета</p>
</div>
<script>
const widgetDiv = document.getElementById('myCustomWidget');
widgetDiv.focus();
</script>
2. Программная установка фокуса с помощью JavaScript
После того как элементу задан tabindex, вы можете управлять фокусом методами .focus() и .blur().
const focusableDiv = document.querySelector('.my-div[tabindex]');
focusableDiv.focus();
focusableDiv.blur();
function openModal() {
const modal = document.getElementById('modal');
modal.classList.remove('hidden');
modal.focus();
}
let previousActiveElement;
function openModal() {
previousActiveElement = document.activeElement;
const modal = document.getElementById('modal');
modal.focus();
}
function closeModal() {
const modal = document.getElementById('modal');
modal.classList.add('hidden');
previousActiveElement.focus();
}
3. Стилизация состояния фокуса (ОЧЕНЬ ВАЖНО!)
Если элемент получает фокус, пользователь должен это видеть. Обязательно добавляйте стили для псевдокласса :focus (а лучше — для :focus-visible, чтобы стили появлялись только при фокусе с клавиатуры, а не при клике мышью).
.my-div:focus {
outline: none;
}
.my-div:focus {
outline: 3px solid #4a90e2;
outline-offset: 2px;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.5);
}
.my-div:focus-visible {
outline: 3px solid #4a90e2;
outline-offset: 2px;
}
4. Практические сценарии и лучшие практики
Сценарий 1: Управление фокусом в модальном окне (Modal Dialog)
Это классический паттерн доступности (ARIA Live Regions).
- При открытии модалки задать
tabindex="-1" и role="dialog" или role="alertdialog" основному контейнеру.
- Сразу же вызвать
.focus() на этом контейнере.
- Запереть фокус внутри модалки, отслеживая нажатие
Tab и циклически перемещая фокус между фокусируемыми элементами модалки.
- При закрытии вернуть фокус на элемент, который вызвал открытие модалки.
Сценарий 2: Прокрутка к элементу
element.focus() также вызывает прокрутку области просмотра к этому элементу (с учётом его scroll-margin). Это можно использовать как альтернативу element.scrollIntoView().
document.getElementById('section-2').focus({ preventScroll: false });
document.getElementById('section-2').focus({ preventScroll: true });
Сценарий 3: Кастомный интерактивный компонент
Если вы создаёте, например, свой div, который ведёт себя как кнопка, лучше использовать семантический элемент <button>. Но если архитектура не позволяет:
- Добавьте
div атрибуты role="button", tabindex="0".
- Обрабатывайте клики и нажатия
Enter/Space (keydown событие).
- Обязательно обеспечьте визуальный
:focus стиль.
Критические замечания и выводы
- Доступность (A11Y): Слепой пользователь со скринридером, попадая на
<div tabindex="0">, услышит только "блок". Это неинформативно. Всегда добавляйте ARIA-атрибуты (aria-label, aria-labelledby, role), чтобы описать роль и назначение элемента.
<div
id="customAlert"
tabindex="-1"
role="alert"
aria-live="assertive"
aria-label="Важное уведомление"
>
Ваши изменения сохранены!
</div>
- Нарушение потока табуляции: Добавление
tabindex="0" или положительного значения для декоративных <div> категорически нарушает логику навигации с клавиатуры. Делайте это только для действительно интерактивных виджетов.
- Приоритет: Всегда спрашивайте себя: "А нельзя ли вместо
<div> использовать нативный фокусируемый элемент (<button>, <a>, <input>)?" Нативные элементы уже имеют встроенную семантику, управление с клавиатуры и доступность.
Итог: Сфокусироваться на <div> технически просто через tabindex="-1" и метод .focus(). Однако ключевая задача — делать это осознанно, всегда обеспечивая визуальную обратную связь и не забывая о пользователях, которые полагаются на клавиатуру и скринридеры. Управление фокусом — это мощный инструмент, который делает ваше веб-приложение по-настоящему профессиональным и инклюзивным.