Доступна форма - та, яку можна заповнити з клавіатури й зрозуміти з екранним читачем. Більшість потрібного дає правильний HTML, а Vue лише має не зламати його.
1. Мітка для кожного поля, пов'язана з полем:
<script setup>
import { useId } from 'vue'
const id = useId()
</script>
<template>
<label :for="id">Email</label>
<input :id="id" v-model="form.email" type="email" autocomplete="email" required />
</template>
Плейсхолдер - не мітка: він зникає при введенні й часто має низький контраст. useId() (Vue 3.5) генерує стабільний id, однаковий на сервері й у браузері при SSR.
2. Помилка, пов'язана з полем:
<input
:id="id"
v-model="form.email"
:aria-invalid="errors.email ? 'true' : undefined"
:aria-describedby="errors.email ? `${id}-error` : undefined"
/>
<p v-if="errors.email" :id="`${id}-error`">{{ errors.email[0] }}</p>
aria-invalidповідомляє, що значення некоректне;aria-describedby- екранний читач прочитає текст помилки разом з назвою поля;- помилка не повинна передаватися лише кольором (червона рамка) - потрібен текст.
3. Фокус на першому полі з помилкою після відправки:
import { nextTick } from 'vue'
async function onInvalid() {
await nextTick() // дочекатися рендеру повідомлень
document.querySelector<HTMLElement>('[aria-invalid="true"]')?.focus()
}
Без цього користувач клавіатури чи екранного читача натискає «Зберегти» - і нічого не відбувається з його точки зору.
4. Зведення помилок для довгих форм: блок з role="alert" нагорі зі списком помилок-посилань на поля.
Ще кілька правил:
<button type="submit">у<form>, а неdivз@click- тоді працює Enter і екранні читачі розуміють, що це форма;- групи перемикачів - у
<fieldset>з<legend>; autocomplete(email,new-password,one-time-code) - менеджери паролів і мобільні клавіатури;- стан відправки -
aria-busyчи текст на кнопці, а не лише спінер; - не вимикайте кнопку відправки до заповнення всіх полів: користувач не розуміє, чого бракує. Краще дозволити натиснути й показати помилки.
Перевірка: пройти форму лише з клавіатури (Tab, Enter, Space) і запустити axe DevTools чи Lighthouse.