Подписи
DrawerContent не задаёт себе имя сам. Дать имя выдвижной панели (Drawer) — ваша задача, и это обязательно: панель без имени недоступна, потому что скринридеры объявляют её просто как «dialog».
- Сошлитесь на видимый заголовок через
aria-labelledbyнаDrawerContentили задайтеaria-label, если видимого заголовка нет. - Если панель отвечает за конкретную задачу, заголовок должен прямо её описывать.
import { useId, type CSSProperties } from 'react';
import {
Badge,
Button,
Drawer,
DrawerClose,
DrawerContent,
DrawerTrigger,
Heading,
Icon,
IconButton,
Text,Поведение клавиатуры
| Клавиша | Действие |
|---|---|
| EnterSpace | На триггере: открывает панель. Фокус получает сама панель или дочерний элемент с autoFocus. |
| TabShift + Tab | Переносит фокус на следующий или предыдущий элемент управления внутри панели. Страница за ней инертна, и фокус на неё не попадает. |
| Escape | Закрывает панель и возвращает фокус на элемент, который её открыл. С closedBy='none' ничего не делает. |
Во вложенных панелях Escape закрывает только верхнюю.
Поведение фокуса
- При открытии фокус должен переходить внутрь панели.
- При закрытии фокус должен разумно возвращаться на исходный триггер или равнозначное действие.
- Стеки вложенных панелей требуют настоящего интеграционного тестирования, а не изолированных допущений.
Управление фокусом обеспечивает нативный <dialog>: пока панель открыта, остальная страница инертна, Tab остаётся внутри панели (но может попасть в интерфейс браузера), а при закрытии фокус возвращается на элемент, который был в фокусе до открытия.
При открытии фокус получает сама панель, поэтому ничего внутри не подсвечивается, а скринридеры объявляют её заголовок; Tab переводит фокус на первый элемент управления. Чтобы сфокусировать дочерний элемент, например первое поле формы, задайте ему autoFocus.
Семантика для скринридеров
- Браузер предоставляет панель как
role=dialogсaria-modal, а имя она получает из вашегоaria-labelledbyилиaria-label. - Триггер предоставляет
aria-haspopup='dialog'иaria-expanded. - У
DrawerCloseнет подписи по умолчанию, поэтому кнопке только с иконкой внутри него нуженaria-label; встроенных строк в библиотеке нет. - Назначение панели должно быть понятным.
- Длинные панели всё равно должны восприниматься как одна цельная задача в оверлее, а не как оторванный фрагмент страницы.
Семантика форм
- Панели часто содержат формы, но семантика формы принадлежит элементам управления внутри панели.
- Состояния ошибок и обязательные поля должны оставаться видимыми, даже когда панель прокручивается.
- Кнопки в
<form method="dialog">закрывают панель черезonChangeOpen(false), аvalueкнопки отправки становитсяreturnValueдиалога. Это работает и сclosedBy='none'.
Риски доступности
- Панель без
aria-labelledbyилиaria-label. - Длинное содержимое без понятной возможности прокрутки.
- Вложенные оверлеи без повторной проверки возврата фокуса.