Radix UI предоставляет механизмы для управления фокусом
элементов интерфейса, что критично для доступности и удобства
навигации с клавиатуры. Любой интерактивный компонент, будь то меню,
модальное окно или вкладка, должен корректно обрабатывать
фокус, чтобы пользователь мог перемещаться по элементам с
помощью клавиш Tab, Shift+Tab и стрелок.
В Radix UI фокус задаётся через свойство
focus, а также с помощью специальных компонентов и
хуков, которые автоматически следят за активным элементом. Внутренний
фокус может быть либо контейнерным (фокус внутри
компонента), либо глобальным (фокус на документе).
import { useFocusRing } from '@radix-ui/react-focus';
function FocusableButton() {
const { isFocused, focusProps } = useFocusRing();
return (
<button {...focusProps} className={isFocused ? 'focused' : ''}>
Нажми меня
</button>
);
}
Здесь useFocusRing обеспечивает отслеживание
состояния фокуса и автоматически добавляет нужные
атрибуты ARIA для доступности.
Когда открывается модальное окно или всплывающее меню, важно
захватить фокус, чтобы пользователь не мог случайно
переместиться на элементы за пределами компонента. В Radix UI это
реализуется через контейнеры с фокус-трапом
(FocusScope) или модальные компоненты
(Dialog).
import * as Dialog from '@radix-ui/react-dialog';
function Modal() {
return (
<Dialog.Root>
<Dialog.Trigger>Открыть модалку</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title>Заголовок</Dialog.Title>
<Dialog.Description>Описание модалки</Dialog.Description>
<button>Закрыть</button>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
Escape по умолчанию закрывает диалог, возвращая
фокус к Dialog.Trigger.Radix UI поддерживает циклический фокус внутри модального окна, что позволяет пользователю обходить элементы только внутри окна без выхода наружу.
Для компонентов, таких как Tabs, DropdownMenu, Accordion, важно корректно реализовать навигацию стрелками. Radix UI предоставляет встроенную логику:
ArrowUp / ArrowDown — перемещение по
вертикальным спискам.ArrowLeft / ArrowRight — перемещение по
горизонтальным вкладкам.Home / End — переход к первому или
последнему элементу.Enter / Space — активация выбранного
элемента.import * as Tabs from '@radix-ui/react-tabs';
<Tabs.Root defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Вкладка 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Вкладка 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Контент 1</Tabs.Content>
<Tabs.Content value="tab2">Контент 2</Tabs.Content>
</Tabs.Root>
Radix автоматически управляет фокусом при переключении вкладок и обеспечивает доступность с клавиатуры без дополнительного кода.
FocusScope позволяет создавать области с
ограниченным фокусом, что особенно полезно для кастомных
всплывающих меню или многоуровневых модальных окон. Можно управлять:
import { FocusScope } from '@radix-ui/react-focus-scope';
<FocusScope trapped>
<input placeholder="Имя" />
<input placeholder="Фамилия" />
<button>Отправить</button>
</FocusScope>
Параметр trapped активирует цикл
фокуса, предотвращая выход за пределы области.
tabIndex и
ARIAДля корректного управления фокусом важно правильно использовать:
tabIndex={0} — элемент доступен через
Tab.tabIndex={-1} — элемент может получить
фокус программно, но пропускается при обходе клавишами.aria-modal,
aria-labelledby, aria-describedby.Radix UI компоненты автоматически добавляют большинство необходимых ARIA-атрибутов, но для кастомных элементов важно следить за их соответствием.
tabIndex > 0 — это нарушает естественный
порядок табуляции.FocusScope для всех всплывающих
окон.Radix UI обеспечивает готовые, доступные по умолчанию механизмы управления фокусом и клавиатурой, позволяя сосредоточиться на логике приложения, не реализуя вручную сложные сценарии обхода элементов и захвата фокуса.