From 4f2d7c01f9110b92ff9848b3940aa6dad8eb4eea Mon Sep 17 00:00:00 2001 From: Andrey Medvedev Date: Wed, 5 Feb 2025 12:36:30 +0300 Subject: [PATCH] fix(Pagination):Update a11y labels (#8237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit На основе обратной связи из #4737: - оставляем только слово "Страницы" как значение по умолчанию у свойства `navigationLabel` (заголовок, `label` всего `Pagination`) - убираем значение по умолчанию из свойства-функции `getPageLabel`, которое рендерило aria-label для кнопок пагинации. Так как дополнительный текст для кнопок создаёт избыточную информацию. Возможно, что стоит задеприкейтить эту функцию. Но пока оставлю. - связываем контенер `nav` с заголовком компонента через `aria-labelledby`, чтобы упростить выполнение условия спецификации, в котором говорится, что при наличии более одного `nav` элемента на странице, каждый элемент должен иметь `aria-label`. Теперь для выполнения этого условия достаточно будет проставить соответстующий `navigationLabel`. - добавили раздел по доступности где перечислены все эти тонкости. --- .../src/components/Pagination/Pagination.tsx | 25 +++++++++++++++---- .../PaginationPage/PaginationPageButton.tsx | 6 ++--- .../vkui/src/components/Pagination/Readme.md | 10 ++++++++ .../vkui/src/components/Pagination/utils.ts | 3 --- 4 files changed, 33 insertions(+), 11 deletions(-) delete mode 100644 packages/vkui/src/components/Pagination/utils.ts diff --git a/packages/vkui/src/components/Pagination/Pagination.tsx b/packages/vkui/src/components/Pagination/Pagination.tsx index 40e8e9d508..46f2991110 100644 --- a/packages/vkui/src/components/Pagination/Pagination.tsx +++ b/packages/vkui/src/components/Pagination/Pagination.tsx @@ -19,7 +19,6 @@ import { PaginationPageButton, } from './PaginationPage/PaginationPageButton'; import { PaginationPageEllipsis } from './PaginationPage/PaginationPageEllipsis'; -import { getPageLabelDefault } from './utils'; import styles from './Pagination.module.css'; export interface PaginationProps extends Omit, 'onChange'> { @@ -78,6 +77,12 @@ export interface PaginationProps extends Omit Note: По возможности лучше не использовать, + * так как компонент и так проставляет номер страницы в разметку, + * что достаточно для пользователей скринридеров. + * Дополнительная информация скорее будет избыточна, + * так как будет зачитываться для каждой кнопки при перемещении по списку. */ getPageLabel?: (isCurrent: boolean) => string; onChange?: (page: number, event: React.MouseEvent) => void; @@ -119,8 +124,8 @@ export const Pagination = ({ prevButtonCaption = 'Назад', nextButtonCaption = 'Вперёд', navigationButtonsStyle = 'icon', - getPageLabel = getPageLabelDefault, - navigationLabel = 'Навигация по страницам', + getPageLabel, + navigationLabel = 'Страницы', navigationLabelComponent = 'h2', prevButtonLabel = 'Перейти на предыдущую страницу', nextButtonLabel = 'Перейти на следующую страницу', @@ -210,9 +215,19 @@ export const Pagination = ({ [currentPage, disabled, getPageLabel, handleClick, renderPageButton, sizeY, pageButtonTestId], ); + const navigationLabelId = React.useId(); + return ( - - {navigationLabel} + + + {navigationLabel} +
  • { const { isCurrent = false, - getPageLabel = getPageLabelDefault, + getPageLabel, children, className, disabled, @@ -40,6 +39,7 @@ const getTappablePropsFromPaginationPage = ( sizeY, }); + const pageLabel = getPageLabel?.(isCurrent); return { 'className': classNames(pageClassNames, className), 'activeMode': styles.stateActive, @@ -49,7 +49,7 @@ const getTappablePropsFromPaginationPage = ( 'disabled': disabled, 'children': ( - {getPageLabel(isCurrent)} + {pageLabel && {pageLabel} } {children} ), diff --git a/packages/vkui/src/components/Pagination/Readme.md b/packages/vkui/src/components/Pagination/Readme.md index 431c2bcd2f..93b79e23d2 100644 --- a/packages/vkui/src/components/Pagination/Readme.md +++ b/packages/vkui/src/components/Pagination/Readme.md @@ -6,6 +6,16 @@ > При ширине `< 380px` рекомендуется отключать `siblingCount` передав в него значение `0`. +## Цифровая доступность (a11y) + +В вёрстке `Pagination` используется HTML тэг `nav`. + +По спецификации, если на странице несколько `nav` или элементов с ролью `navigation`, каждому стоит задать своё уникальное имя с помощью `aria-label` или `aria-labelledby` (см. [role navigation](https://doka.guide/a11y/role-navigation/#kak-pishetsya)). + +Так как `Pagination` уже связан с меткой блока навигации, который задаётся через свойство `navigationLabel`, с помощью `aria-labelledby`, то для каждого `Pagination` достаточно задать свой `navigationLabel`. Если `Pagination` элементы содержат одинаковые ссылки, то и `navigationLabel` должны быть одинаковыми. + +В `navigationLabel` стоит избегать слова `Навигация` или слов близких по значению, так как скринридер и так зачитывает это видя тег `nav` или `role="navigation"`. Лучше ограничиться чем-то вроде `Страницы`. + ## `usePagination` Для полной кастомизации можно использовать хук `usePagination()`. Возвращает массив типа `[1, 2, 3, 4, 5, 'end-ellipsis', 8]`. Принимает почти те же параметры, что и `Pagination`. diff --git a/packages/vkui/src/components/Pagination/utils.ts b/packages/vkui/src/components/Pagination/utils.ts deleted file mode 100644 index 742ae970f5..0000000000 --- a/packages/vkui/src/components/Pagination/utils.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getPageLabelDefault(isCurrent: boolean): string { - return isCurrent ? `Страница` : `Перейти на страницу`; -}