Вбудована валідація і UX помилок
1) Принципи
1. Передиктивна допомога, не покарання. Показуємо, як ввести коректно, до помилки.
2. Не втрачати дані. Будь-яка помилка не знищує введене; підтримуємо «Скасувати «/» Повторити ».
3. Момент показу.
До введення: helper text (правила і приклади).
Під час: м'які хінти/маска/автопідстановка.
Після (blur/submit): чітка помилка з інструкцією «як виправити».
4. Економія уваги. Одне повідомлення - одна причина і дія.
5. Доступність. Текст + іконка/колір, зв'язок з полем через ARIA, фокус до першого помилкового поля.
2) Шари валідації
Клієнтська синхронна: формат, довжина, обов'язковість, маска. Швидка і дешева.
Клієнтська асинхронна: унікальність логіна, перевірка BIN/IBAN, API-підказки. З дебаунсом.
Серверна: бізнес-правила, ліміти, ризик-скоринг, авторизація/права. Істина останньої інстанції.
Правило: навіть при ідеальній клієнтській перевірці сервер підтверджує і формує остаточний текст.
3) Таймінги і дебаунс
Валідація на blur → миттєвий фідбек ≤ 100 мс.
Асинхронна перевірка - дебаунс 250-400 мс після зупинки введення.
Підтвердження успішності - лаконічне («Ок») або зелена іконка; без «салютів».
На'submit'показуємо список помилок і переносимо фокус до першої.
js const debounce = (fn, ms=300)=>{let t;return (...a)=>{clearTimeout(t);t=setTimeout(()=>fn(...a),ms)}}
4) Копірайтинг помилок
Шаблон: причина → як виправити → альтернатива (якщо є).
Добре: "Пароль коротший за 8 символів. Додайте ще символи або використовуйте фразу".
Добре: "IBAN виглядає некоректно. Перевірте довжину і символи: A–Z, 0–9».
Погано: «Неправильне введення».
Не звинувачуйте користувача; уникайте жаргону і кодів.
У чутливих зонах (платежі/КУС) уникаємо деталей, що розкривають безпеку.
5) Патерни показу повідомлень
5. 1 У поля (inline)
`aria-invalid="true"`, текст в `aria-describedby`.
Коротко, конкретно; без довгих абзаців.
Колір + іконка, але сенс - в тексті.
5. 2 Під формою (summary)
Список всіх помилок з якорями до полів.
Кнопка «Перейти до помилки »/клік по пункту переносить фокус.
5. 3 В процесі відправки
Блокуємо повторне натискання (state'busy').
При таймауті 3-5 с - «Очікуємо підтвердження»... з безпечним повтором.
6) Маски, автопідказки та коректори
Маски не повинні заважати вставці/редагуванню. Дозволяйте вільне введення, нормалізуйте під капотом.
Автопідказки: показуйте приклади форматів, placeholder як підказка, а не «обов'язкова» частина.
Нормалізація: trimming прогалин, уніфікація регістрів, авто-формат (наприклад,'+ 1 (___) ___ - ____') - але у вихідні дані зберігайте «чисту» версію.
7) Доступність (A11y)
Зв'язок: 'label'↔'input', помилки в'aria-describedby'.
Критичні -'role = «alert»', інформаційні -'role = «status»'.
Повертаємо фокус до помилкового поля,':focus-visible'бачимо.
Контраст тексту/іконок ≥ AA; сенс не залежить тільки від кольору.
html
<label for="email">Email</label>
<input id="email" name="email" aria-describedby="email-help email-err">
<small id="email-help">Например: user@domain.tld</small>
<p id="email-err" class="field-error" role="alert" hidden>Проверьте формат email</p>
8) Міжнародні формати та локалізація
Імена/адреси: допускайте різні алфавіти, довжини, апострофи, дефіси.
Дати/валюти/номери: використовуйте локальні формати введення і строгі внутрішні структури зберігання (ISO/число центів).
Телефон: введення в міжнародному форматі «+ CC», автопідсказка по країні.
Мова повідомлень: короткі, культурно нейтральні; закладайте + 20-30% довжини рядка.
9) Безпека і приватність
Не показуйте, що аккаунт існує/не існує - загальний текст: «Якщо email зареєстрований, ми надішлемо листа».
Маскуйте чутливі дані (PAN, паспорт).
На критичних кроках (ставка/платіж) використовуйте ідемпотентність і «безпечні повтори».
Логи - з ID кореляції без PII в повідомленнях.
10) Збереження прогресу
Автосейв чернетки (локально/на сервері).
При помилці відправки - форма залишається заповненою; пропонується повтор пізніше.
При багатокрокових процесах (KYC) - зберігайте завершені кроки.
11) Асинхронна валідація
Дебаунс 250-400 мс; показуємо «перевіряємо»... біля поля, не блокуючи весь екран.
Ясна індикація успіху/неуспіху без «смикань» макета.
Таймаут мережі → "Не вдалося перевірити. Продовжити з ризиком?" (якщо допустимо) або «Повторити».
js const checkUsername = debounce(async (v)=>{
state.usernameChecking = true;
const ok = await api.unique('username', v).catch(()=>null);
state.usernameChecking = false;
state.usernameValid = ok === true;
}, 300);
12) Платіжні форми та KYC (специфіка)
Карти: формат PAN, термін, CVC - валідація в міру введення; помилки - без розкриття причини відхилення банком.
А2А/гаманці: перевірка допустимості по країні/лімітам, чіткі тексти про комісії/терміни.
KYC: покрокові вимоги до фото/документів, передогляд, розмір/тип файлу, терміни перевірки, приватність.
Відповідальна гра: повідомлення нейтральні, з діями «Встановити ліміт «/« Допомога ».
13) Антипатерни
Показ помилок «на кожен символ» без дебаунсу.
Скидання форми при помилці.
Повідомлення «Невірний ввід» без зазначення поля/правила.
Критична інформація тільки кольором/іконкою.
Блокування всієї сторінки заради перевірки одного поля.
Відсутність офлайн-режиму і повторів при мережевих збоях.
14) Токени дизайн-системи (приклад)
json
{
"validation": {
"debounceMs": 300,
"blurFeedbackMs": 100,
"asyncTimeoutMs": 5000,
"summaryMaxItems": 6
},
"a11y": {
"useAriaDescribedby": true,
"errorRole": "alert",
"statusRole": "status"
},
"visual": {
"fieldGap": 8,
"iconSize": 16,
"borderRadius": 10
}
}
15) Сніпети реалізації
Поле з inline-валідатором (формат + серверна перевірка):js const rules = {
email: v => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) "Проверьте формат email"
};
async function validateEmail(v){
const fmt = rules.email(v);
if (fmt!== true) return fmt;
try {
const r = await fetch(`/api/email/check?v=${encodeURIComponent(v)}`);
const { allowed } = await r.json();
return allowed? true: "Этот email недоступен. Выберите другой.";
} catch {
return "Не удалось проверить. Повторите позже.";
}
}
Зведення помилок з фокусом:
ts function focusFirstError() {
const err = document.querySelector('[aria-invalid="true"]');
if (err) err.focus({ preventScroll:false });
}
Збереження чернетки локально:
js const saveDraft = debounce(form => localStorage.setItem('draft', JSON.stringify(Object.fromEntries(new FormData(form)))), 500);
form.addEventListener('input', ()=>saveDraft(form));
16) Метрики та контроль
Time-to-Fix (час від помилки до виправлення).
Error rate по полях і з причин (формат/ліміти/сервер).
Повторне відправлення (retry success rate).
Частка покинутих форм і глибина кроку.
Заповненість підказками: CTR «Детальніше», частота приховувань підказок.
17) QA-чек-лист
A11y
- Фокус переходить до першого помилкового поля;'aria-describedby '/' aria-invalid'виставлені.
- Контраст ≥ AA; повідомлення не залежать тільки від кольору.
Поведінка
- Вбудована валідація з дебаунсом; помилки з'являються не раніше blur (крім критичних масок).
- На submit формується зведення, поля не очищаються.
- Асинхронні перевірки не блокують сторінку; є таймаут і повтор.
Текст
- Причина + як виправити; без кодів/вини.
- Локалізація не ламає макет; Приклади актуальні.
Безпека
- Немає витоків PII в повідомленнях; не розкриваємо існування акаунта.
- Ідемпотентність для критичних операцій.
18) Документація в дизайн-системі
Компоненти: `FieldError`, `FormSummary`, `HelperText`, `BusyButton`.
Карти правил для типових полів (email, телефон, пароль, адреса, IBAN, дата).
Гайди щодо дебаунсу, асинхронної перевірки та офлайн-поведінки.
Шаблони текстів для частих помилок і приклади «до/після».
Коротке резюме
Вбудована валідація - це про предиктивну допомогу, чіткі інструкції та дбайливе ставлення до даних. Перевіряйте локально і на сервері, показуйте помилки в потрібний момент з конкретними діями, поважайте доступність і приватність, зберігайте прогрес і використовуйте дебаунс. Так форми стають доброзичливими, а помилки - швидкими і виправними.