intermediate
Управление фокусом
Переносите, удерживайте, восстанавливайте и визуально оформляйте focus для dialog, смены route, ошибок валидации и кастомных виджетов.
Управление фокусом намеренно переносит клавиатурное внимание: в открытый dialog, внутри trap пока модалка активна, обратно на trigger при закрытии и на ошибки валидации после submit. Смена route в SPA должна переносить focus на main или объявлять новый экран.
function openDialog(trigger: HTMLElement, dialog: HTMLElement) {
lastFocus = trigger;
dialog.showModal();
dialog.querySelector<HTMLElement>('[data-autofocus]')?.focus();
}
function closeDialog() {
dialog.close();
lastFocus?.focus();
}
| Сценарий | Паттерн | |----------|---------| | Открытие modal | Focus на первый focusable или titled region | | Закрытие modal | Возврат focus на trigger | | Client route | Focus на `<h1>` или `main` с `tabindex="-1"` | | Inline error | Focus на первое невалидное поле + `aria-invalid` |
Focus trap должен допускать Escape и возврат focus — trap без выхода не проходит WCAG и ломает реальных пользователей.
На интервью: autofocus vs programmatic focus; `inert` vs библиотеки trap; focus после навигации React Router.
Типовые ошибки: modal без переноса focus; focus на удалённом узле; блокировка scroll без focus; несколько trap одновременно.
Компромисс — полировка анимаций против немедленного keyboard-контекста после смены UI.
Чеклист:
- Сохранять и восстанавливать focus trigger для overlay.
- Переносить focus при route и крупных сменах состояния.
- Сочетать перенос focus с live announcements при необходимости.
- Прогон tab cycle внутри dialog end to end.