Доступні форми: 12 правил для розробників (з прикладами коду)
12 практичних правил для accessible forms: label, autocomplete, aria-describedby, валідація, focus, контраст. З прикладами HTML/ARIA для login, checkout та контакт-форм.
Андрій Вдовин
Чому форми — критична точка
Форми — це місце, де користувач реально щось робить: реєструється, оформлює замовлення, надсилає звернення. За даними WebAIM Million 2025, 49% помилок Level A на середньому сайті — це проблеми форм (відсутні labels, неконтрастні поля, недоступні помилки). Втрата конверсії від поганої форми не помітна у Google Analytics, але вона є.
1. Кожне поле має програмний label
Скрін-рідер прочитає поле тільки якщо воно зв'язане з текстом — через елемент <label for="id"> або атрибут aria-label. Placeholder сам по собі не є label.
<!-- ❌ Погано: лише placeholder -->
<input type="email" placeholder="Email">
<!-- ✅ Добре: label прив'язаний до input -->
<label for="email">Email</label>
<input id="email" type="email">2. Placeholder — це підказка, не заміна label
Placeholder зникає коли користувач починає вводити текст. Людина з когнітивними порушеннями може забути, що саме потрібно ввести. Використовуйте placeholder для прикладу формату (наприклад, «+380 50 123 45 67»), а не для опису поля.
3. Правильні input type для мобільних
type="email", type="tel", type="number", inputmode="numeric" — мобільна клавіатура одразу покаже потрібний набір символів. Це і UX-перемога, і доступність для людей з моторними порушеннями.
4. Атрибут autocomplete для відомих полів
WCAG 2.1 success criterion 1.3.5 вимагає вказувати autocomplete для полів зі стандартним значенням (name, email, address, tel). Це допомагає браузерам автозаповнювати форми і дозволяє людям з когнітивними порушеннями уникнути ручного введення.
<input id="name" name="name" autocomplete="name">
<input id="email" name="email" autocomplete="email">
<input id="tel" name="tel" autocomplete="tel">5. Обов'язкові поля позначені і візуально, і програмно
Зірочка червоного кольору поряд з label — недостатньо: вона не зчитується скрін-рідером і не помітна дальтонікам. Використовуйте атрибут required та слово «обов'язкове» або символ із aria-label.
<label for="email">
Email <span aria-label="обов'язкове" className="text-red-600">*</span>
</label>
<input id="email" type="email" required>6. Помилки валідації прив'язані до поля через aria-describedby
Просто червоний текст під полем — невидимий для скрін-рідера. Зв'яжіть повідомлення з полем через aria-describedby, додайте aria-invalid="true" на поле з помилкою, і використайте role="alert" або aria-live="polite" для оголошення.
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error" role="alert" className="text-red-600 text-sm">
Невірний формат email
</p>7. Групи radio і checkbox — у fieldset з legend
Скрін-рідер озвучить legend перед кожною опцією: «Спосіб доставки, нова пошта», «Спосіб доставки, кур'єр». Без fieldset користувач не зрозуміє, до якого питання належать опції.
<fieldset>
<legend>Спосіб доставки</legend>
<label><input type="radio" name="ship" value="np"> Нова пошта</label>
<label><input type="radio" name="ship" value="ukr"> Укрпошта</label>
<label><input type="radio" name="ship" value="courier"> Кур'єр</label>
</fieldset>8. Видимий focus-індикатор
outline: none без альтернативи — найгірша практика. Користувачі з клавіатурної навігацією загубляться у формі. Залишайте outline або робіть власний помітний indicator (border, ring, shadow) з контрастом 3:1.
9. Контраст тексту і полів — 4.5:1 / 3:1
Сірий текст label на білому фоні (#999 на #fff) має контраст 2.85:1 — це провал WCAG. Текст у полі: мінімум 4.5:1. Бордер поля з фоном: мінімум 3:1 за WCAG 2.1 criterion 1.4.11 Non-text Contrast.
10. Touch targets ≥ 44×44 px
Маленькі checkbox і radio на мобільних — біль для людей з тремором або великими пальцями. WCAG 2.2 criterion 2.5.8 Target Size (Minimum) вимагає 24×24 CSS-пікселів, але рекомендована практика — 44×44.
11. Не очищати поля при помилці submit
Найболючіший антипатерн: користувач заповнив 10 полів, ввів неправильний email — і всі дані зникли. Зберігайте всі введені значення, помічайте лише проблемне поле. WCAG 3.3.4 «Error Prevention» прямо цього вимагає для фінансових і юридичних форм.
12. Заголовок над формою і логічний порядок tab
<h2>Зворотний зв'язок</h2> над формою допомагає скрін-рідерам перейти прямо до неї через клавішу H. Порядок полів у HTML має відповідати візуальному — інакше клавіатурна навігація буде стрибати по сторінці. Уникайте tabindex з позитивними значеннями — це ламає природний порядок.
Швидкий тест за 60 секунд
Натисніть Tab по формі від початку до кінця. Бачите, де знаходиться focus? Чи можете заповнити форму без миші? Якщо ні — у вас порушені пункти 8, 12 і, ймовірно, 1.
Автоматизована перевірка
Lighthouse і axe DevTools знаходять близько 30% порушень — ті, що автоматично детектуються (відсутній label, недостатній контраст, дублювання id). Решту знаходить ручний прохід клавіатурою + скрін-рідер. InclusiveWeb Audit поєднує обидва підходи: автомат + перевірки шаблонів сторінок з груповою аналітикою.
Часті питання
Чи можна обійтись placeholder без label?
Ні, навіть якщо візуально красиво. Placeholder зникає при введенні, не зчитується частиною скрін-рідерів і має слабкий контраст за замовчуванням. Якщо label псує дизайн — приховайте його через .sr-only, а не приберіть взагалі. Так він залишиться для assistive tech.
Як зробити floating labels доступними?
Floating labels — це звичайний label з CSS-анімацією. Доступні, якщо: 1) HTML-структура зберігає семантику (label йде до або після input), 2) контраст плаваючого label достатній і у активному, і в неактивному стані, 3) при автозаповненні label не перекриває значення.
Чи треба показати помилки одразу при введенні (real-time)?
Найкраща UX-практика: валідація на події blur (поле втратило focus), а не change (кожна буква). Користувач не повинен бачити «Невірний email» поки він не завершив набирати. Для повторної перевірки після submit — валідуйте всю форму і знайдіть перше проблемне поле.
Чи можна використовувати CAPTCHA?
Так, але з обережністю. Класична CAPTCHA з текстом — провал для незрячих. Доступніші варіанти: hCaptcha з аудіо-альтернативою, Cloudflare Turnstile (невидимий для більшості користувачів), reCAPTCHA v3 (score-based, без challenge). Завжди надавайте альтернативний канал звернення (email, телефон), якщо CAPTCHA блокує користувача.
Джерела та посилання
- W3C WAI — Forms Tutorial
- WebAIM — Creating Accessible Forms
- WCAG 2.1 — 1.3.5 Identify Input Purpose
- WCAG 2.2 — 2.5.8 Target Size (Minimum)
- WebAIM Million Report 2025
Останнє оновлення: 11.05.2026