Skip to content

feat(Button): improve a11y with loading state#9312

Merged
EldarMuhamethanov merged 9 commits intomasterfrom
e.muhamethanov/8750/button-a11y-improve
Dec 24, 2025
Merged

feat(Button): improve a11y with loading state#9312
EldarMuhamethanov merged 9 commits intomasterfrom
e.muhamethanov/8750/button-a11y-improve

Conversation

@EldarMuhamethanov
Copy link
Copy Markdown
Contributor

@EldarMuhamethanov EldarMuhamethanov commented Dec 17, 2025


  • Unit-тесты
  • Release notes

Описание

Исправлена проблема доступности кнопок со свойством loading. Ранее при установке loading={true} кнопка становилась disabled, что приводило к потере фокуса и ухудшению доступности для пользователей скринридеров и клавиатурной навигации.

Теперь кнопки с loading сохраняют фокус, но при этом корректно обрабатывают клики через программную логику. Для ссылок (href) реализована правильная обработка disabled/loading состояний согласно рекомендациям WAI-ARIA.

Изменения

Кнопки (<button>)

  1. Убрана зависимость disabled от loading:

    • Кнопки с loading={true} больше не получают атрибут disabled
    • Это позволяет сохранить фокус на кнопке во время загрузки
  2. Добавлены ARIA-атрибуты:

    • aria-busy="true" - указывает скринридерам о состоянии загрузки
    • aria-hidden="true" на Spinner - скрывает спиннер от скринридеров
  3. Улучшена обработка кликов:

    • Создан handleClick, который предотвращает выполнение обработчика при loading или disabled через e.preventDefault()
    • Вместо onClick={loading ? undefined : onClick} используется программная блокировка

Ссылки (<a> с href)

  1. Правильная обработка disabled/loading состояний согласно WAI-ARIA:

    • При loading={true} или disabled={true} атрибут href удаляется (ссылка становится некликабельной)
    • Добавляется role="link" (так как <a> без href не является ссылкой)
    • Устанавливается aria-disabled="true"
    • Устанавливается aria-busy="true" при loading
  2. Разделение логики для кнопок и ссылок:

    • Для кнопок: disabled={disabled} (без учета loading)
    • Для ссылок: не передается disabled, только aria-disabled

Тесты

Добавлены unit-тесты для проверки:

  • Правильности установки ARIA-атрибутов при различных состояниях
  • Сохранения фокуса на кнопках с loading
  • Корректной обработки ссылок с loading и disabled
  • Блокировки обработчиков кликов при loading

Release notes

Исправления

  • Button:
    • исправлена потеря фокуса при loading={true}
      Кнопки со свойством loading больше не получают атрибут disabled, что позволяет сохранять фокус во время загрузки. Добавлены ARIA-атрибуты (aria-busy, aria-disabled) для правильной работы со скринридерами.
    • добавлено свойство loadingLabel для указания лейбла при loading={true}.
    • улучшена доступность ссылок с loading и disabled согласно WAI-ARIA
      Для ссылок (href) с состоянием loading или disabled теперь корректно удаляется атрибут href, добавляется role="link" и устанавливаются необходимые ARIA-атрибуты для правильной работы с ассистивными технологиями.

@EldarMuhamethanov EldarMuhamethanov requested a review from a team as a code owner December 17, 2025 16:27
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 17, 2025

size-limit report 📦

Path Size
JS 408.05 KB (+0.06% 🔺)
JS (gzip) 125.17 KB (+0.09% 🔺)
JS (brotli) 103.59 KB (+0.02% 🔺)
JS import Div (tree shaking) 811 B (0%)
CSS 372.71 KB (0%)
CSS (gzip) 46.21 KB (0%)
CSS (brotli) 36.59 KB (0%)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 17, 2025

e2e tests

⚠️ Some screenshots were failed. See Playwright Report.

Playwright Report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 17, 2025

📊 Найдены изменения в собранных файлах: Отчет

Commit 1c60fe5

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 17, 2025

👀 Docs deployed

📦 Package ✅

yarn add @vkontakte/vkui@https://development.s3.prodcloud.vk.team/pull/9312/1c60fe5a734a7b69c083012f6852f704d5d41c43/pkg/@vkontakte/vkui/_pkg.tgz

Commit 1c60fe5

@codecov
Copy link
Copy Markdown

codecov bot commented Dec 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.98%. Comparing base (67efe75) to head (1c60fe5).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9312      +/-   ##
==========================================
+ Coverage   94.91%   94.98%   +0.07%     
==========================================
  Files         433      432       -1     
  Lines       11769    11733      -36     
  Branches     4342     4322      -20     
==========================================
- Hits        11170    11145      -25     
+ Misses        599      588      -11     
Flag Coverage Δ
unittests 94.98% <100.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@inomdzhon
Copy link
Copy Markdown
Contributor

  1. Нужно в доку loading и в его JSDoc добавить инфу, что нужно прокидывать aria-label (или VisuallyHidden) при использовании loading, иначе из скринридера не понять что конкретно происходит "занят, кнопка" (прикрепил видео). <Button aria-label="загрузка..." loading>Кнопка</Button>
  2. Может будет отключать состояния наведения и нажатия (прикрепил видео)?
button-loading.mov

В статье https://www.bekk.christmas/post/2023/24/accessible-loading-button есть примеры либ, которые делают доступное состояние loading

@EldarMuhamethanov
Copy link
Copy Markdown
Contributor Author

  1. Нужно в доку loading и в его JSDoc добавить инфу, что нужно прокидывать aria-label (или VisuallyHidden) при использовании loading, иначе из скринридера не понять что конкретно происходит "занят, кнопка" (прикрепил видео). <Button aria-label="загрузка..." loading>Кнопка</Button>

Добавил свойство loadingAriaLabel

2. Может будет отключать состояния наведения и нажатия

Отключил

inomdzhon
inomdzhon previously approved these changes Dec 23, 2025
Copy link
Copy Markdown
Contributor

@inomdzhon inomdzhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:accessibility:

@EldarMuhamethanov EldarMuhamethanov merged commit a0ad260 into master Dec 24, 2025
29 checks passed
@EldarMuhamethanov EldarMuhamethanov deleted the e.muhamethanov/8750/button-a11y-improve branch December 24, 2025 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug][Button]: Разобраться с доступностью loading кнопок

2 participants