Stimulus — это минималистичный JavaScript-фреймворк, предназначенный для добавления динамического поведения к HTML-элементам без создания сложной архитектуры SPA. Одной из ключевых задач при разработке интерактивных интерфейсов является управление фокусом элементов. Правильная работа с фокусом улучшает пользовательский опыт, повышает доступность и обеспечивает корректное взаимодействие с формами, модальными окнами и динамическими компонентами.
В Stimulus управление фокусом осуществляется через
контроллеры, которые связывают HTML-элементы с методами
JavaScript. Контроллеры создаются с помощью класса
Controller и подключаются к элементам через атрибут
data-controller.
<div data-controller="focus">
<input data-focus-target="input" type="text">
<button data-action="click->focus#setFocus">Установить фокус</button>
</div>
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["input"];
setFocus() {
this.inputTarget.focus();
}
}
Ключевые моменты:
data-focus-target указывает, на какой элемент
контроллер может воздействовать.data-action связывает событие с методом контроллера
(click->focus#setFocus).В динамических интерфейсах элементы могут появляться после загрузки
страницы. Для установки фокуса на только что добавленные элементы
используется метод connect контроллера.
connect() {
if (this.hasInputTarget) {
this.inputTarget.focus();
}
}
Этот подход позволяет гарантировать, что пользовательский фокус всегда окажется на нужном элементе, независимо от того, когда элемент добавлен в DOM.
Stimulus поддерживает массивы целей, что удобно для форм с множественными полями. Пример:
static targets = ["input"];
focusFirst() {
if (this.inputTargets.length > 0) {
this.inputTargets[0].focus();
}
}
focusLast() {
if (this.inputTargets.length > 0) {
this.inputTargets[this.inputTargets.length - 1].focus();
}
}
В данном случае inputTargets возвращает массив
всех элементов с target=“input”, что позволяет управлять
порядком фокуса программно.
Для улучшения навигации по форме или модальному окну можно
использовать события focus и blur. Stimulus
позволяет легко обрабатывать их через data-action.
<input data-action="focus->focus#onFocus blur->focus#onBlur">
onFocus(event) {
console.log("Элемент получил фокус:", event.target);
}
onBlur(event) {
console.log("Элемент потерял фокус:", event.target);
}
Это особенно полезно для валидации форм в реальном времени или для управления стилями активных полей.
В интерактивных интерфейсах часто требуется ограничивать фокус
только элементами модального окна (focus trap). В
Stimulus это реализуется путем установки фокуса на первый интерактивный
элемент при открытии и обработки клавиши Tab.
trapFocus(event) {
const focusableElements = this.element.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])");
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (event.key === "Tab") {
if (event.shiftKey && document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
} else if (!event.shiftKey && document.activeElement === lastElement) {
event.preventDefault();
firstElement.focus();
}
}
}
Метод trapFocus можно привязать к событию
keydown всего модального окна. Такой подход обеспечивает
циклическое перемещение фокуса внутри модального окна,
предотвращая случайный выход за пределы диалога.
Если элемент появляется с анимацией, установка фокуса сразу после
добавления может не сработать. В таких случаях применяется
задержка через setTimeout или слушатель
события transitionend.
showElement() {
this.element.classList.add("visible");
this.element.addEventListener("transitionend", () => {
this.inputTarget.focus();
}, { once: true });
}
Это гарантирует, что фокус будет установлен только после завершения анимации появления.
Эффективный контроллер управления фокусом может содержать следующие компоненты:
click,
focus, blur и клавиатурных событий.setFocus,
focusFirst, focusLast,
trapFocus.Такой подход обеспечивает гибкое, модульное и легко расширяемое управление фокусом, что критично для интерактивных веб-приложений.