В интерфейсах с модальными окнами правильная работа с фокусом
критически важна для обеспечения доступности и удобства навигации.
Carbon Components Svelte предоставляет готовые механизмы для управления
фокусом внутри компонентов Modal, позволяя автоматически
переводить фокус на элементы внутри модального окна при его открытии и
возвращать фокус на исходный элемент при закрытии.
Фокус в модальном окне работает по принципу focus trap: пользователь не может покинуть область модального окна при помощи клавиатуры до его закрытия. Это предотвращает случайное взаимодействие с элементами страницы, находящимися вне модального окна.
Компонент Modal в Carbon Components Svelte поддерживает
атрибут initialFocus, который позволяет указать конкретный
элемент, на который должен быть установлен фокус после открытия
модального окна.
<script>
import { Modal, Button } from 'carbon-components-svelte';
let showModal = false;
</script>
<Button on:click={() => showModal = true}>Открыть модальное окно</Button>
<Modal bind:open={showModal} initialFocus="#modal-input">
<div slot="body">
<input id="modal-input" type="text" placeholder="Введите текст..." />
<Button>Сохранить</Button>
</div>
</Modal>
В этом примере при открытии модального окна фокус автоматически
устанавливается на input с id="modal-input".
Если initialFocus не указан, фокус устанавливается на
первый интерактивный элемент внутри модального окна.
После закрытия модального окна важно вернуть фокус на элемент,
который его открыл, чтобы обеспечить непрерывность навигации. Carbon
Components Svelte делает это автоматически, если модальное окно
управляется через привязку состояния bind:open.
<Button id="open-btn" on:click={() => showModal = true}>Открыть</Button>
<Modal bind:open={showModal} initialFocus="#modal-input">
<div slot="body">
<input id="modal-input" type="text" />
<Button>Закрыть</Button>
</div>
</Modal>
После закрытия модального окна фокус возвращается на кнопку с
id="open-btn".
Компонент Modal поддерживает полный контроль над
focus trap. По умолчанию он ограничивает фокус внутри
модального окна, но при необходимости можно использовать проп
disableFocusTrap для отключения этой функциональности:
<Modal bind:open={showModal} disableFocusTrap={true}>
<div slot="body">
<input type="text" />
<Button>Закрыть</Button>
</div>
</Modal>
Отключение focus trap может быть полезно при создании модальных окон с нестандартной навигацией или интеграцией с внешними компонентами, требующими взаимодействия за пределами окна.
Для более сложных форм и интерфейсов важно корректно определять
порядок табуляции. Carbon Components Svelte автоматически учитывает
стандартный порядок элементов в DOM, но для динамически добавляемых
элементов или вложенных компонентов можно использовать атрибут
tabindex:
tabindex="0" — элемент включается в стандартную
последовательность фокуса.tabindex="-1" — элемент исключается из
последовательности, но на него можно программно установить фокус.Пример программного управления фокусом внутри модального окна:
<script>
import { Modal, Button } from 'carbon-components-svelte';
let showModal = false;
function focusButton() {
document.getElementById('modal-btn').focus();
}
</script>
<Button on:click={() => showModal = true}>Открыть модальное окно</Button>
<Modal bind:open={showModal} on:open={() => focusButton()}>
<div slot="body">
<input type="text" placeholder="Введите текст..." />
<Button id="modal-btn">Активная кнопка</Button>
</div>
</Modal>
Здесь после открытия модального окна фокус устанавливается программно на кнопку внутри него, независимо от позиции в DOM.
Компонент Modal поддерживает несколько событий,
связанных с открытием и закрытием, которые позволяют контролировать
поведение фокуса:
on:open — вызывается после открытия модального окна.
Здесь удобно устанавливать начальный фокус.on:close — вызывается при закрытии. Можно использовать
для сохранения состояния фокуса на исходном элементе.on:keydown — позволяет перехватывать клавиши, включая
Tab и Escape, для кастомного управления
фокусом и закрытия окна.При динамическом рендеринге элементов внутри модального окна важно, чтобы элемент, на который устанавливается фокус, уже присутствовал в DOM. Если элемент создаётся асинхронно, необходимо вызывать установку фокуса после завершения рендера:
<script>
import { Modal, Button } from 'carbon-components-svelte';
let showModal = false;
let loaded = false;
function loadContent() {
loaded = true;
setTimeout(() => {
document.getElementById('dynamic-input').focus();
});
}
</script>
<Button on:click={() => { showModal = true; loadContent(); }}>Открыть</Button>
<Modal bind:open={showModal}>
<div slot="body">
{#if loaded}
<input id="dynamic-input" type="text" />
{/if}
</div>
</Modal>
Такой подход гарантирует корректное управление фокусом даже при асинхронной загрузке контента.
Корректное управление фокусом в модальных окнах напрямую влияет на
доступность (a11y). Пользователи клавиатуры и
скринридеров должны иметь возможность полностью взаимодействовать с
содержимым модального окна без случайного выхода за его пределы. Carbon
Components Svelte обеспечивает соответствие стандартам ARIA,
автоматически устанавливая aria-hidden для элементов за
пределами открытого модального окна и управляя focus trap.
Эти инструменты позволяют создавать удобные, доступные и предсказуемые модальные интерфейсы, интегрированные в сложные веб-приложения.