Спроектируй микро-взаимодействия для формы: {{form}}.
Тезис: форма — это диалог, а не анкета. Каждое поле даёт обратную связь в правильный момент.
1. Focus
- Видимый focus ring всегда (даже от мыши; для a11y и keyboard)
- 2px outline + offset 2px, цвет акцента
- Не убирай
:focus-visibleчерезoutline: noneбез замены - Hover ≠ focus: hover мягче, focus заметнее
- При focus поле слегка светлее фона, label поднимается (если floating)
input:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
2. Тайминг валидации
Главный принцип: не ругай, пока пользователь печатает.
| Событие | Когда валидировать | Почему |
|---|---|---|
| onChange | НЕТ для ошибок | пользователь ещё печатает |
| onBlur | ДА — первая проверка | поле "закрылось", момент для фидбэка |
| onChange после ошибки | ДА — но только убирать ошибку | "уже исправляю" |
| onSubmit | ДА — финальный pass + фокус на первое битое | защитная сеть |
Исключение: проверка занятого username/email — async после onBlur + debounce 400ms.
3. Состояния поля
default → focus → typing → blur(valid) → blur(invalid)
↓ ↓
(no error) error shown below
↓
typing (clears error
on first valid char)
Для каждого — визуал:
- default: border нейтральный
- focus: outline ring + чуть светлее фон
- valid: галочка справа в поле, 200ms fade-in, тонкая, не зелёный заборщик
- invalid: border красный + текст ошибки ПОД полем, не в tooltip
- disabled: opacity 0.5, cursor not-allowed
- loading (async check): spinner справа в поле, не блокировать ввод
4. Копия ошибки
[Что не так] + [как починить]
-
❌ "Invalid email"
-
✅ "Похоже, нет '@'. Пример: name@domain.com"
-
❌ "Password too weak"
-
✅ "Добавьте цифру или символ"
5. Успех
- НЕ показывай "✓" на каждое поле — становится шумом
- Показывай только на критичных (email подтверждён, промокод применён)
- Финальный успех формы — переход на следующий экран ИЛИ inline баннер на 4-5 сек
6. Восстановление
- Никогда не очищай поля при ошибке submit
- Auto-save черновика на blur (для длинных форм)
- При навигации назад — сохраняй состояние формы (history API + sessionStorage)
- Сетевая ошибка → toast + retry, форма заполнена
7. Клавиатура и автозаполнение
autocomplete="email","current-password","one-time-code"— не угадывайinputmode="numeric"для PIN, OTP, кодовenterkeyhint="send"/"next"— правильный лейбл Enter на мобильном- Tab order — визуальный порядок, без
tabindex > 0
8. Submit-кнопка
- НЕ disable на основании "форма невалидна" — пользователь не поймёт почему
- Лучше: разрешить клик, на submit показать summary ошибок + фокус на первое битое поле
- Во время submit: disable + спиннер слева в кнопке, текст "Отправляем…"
- Не более 3 секунд без фидбэка — иначе пользователь жмёт ещё раз
Формат вывода
- Таблица "состояние → визуал → событие" для одного поля
- JSX-скелет с правильными
aria-*иautocomplete - Список тайминга валидации с обоснованием
- 3 примера копий ошибок (плохо/хорошо)
Анти-паттерны
- Валидация на каждый keystroke — пользователь видит "Invalid" пока ещё печатает
- Disable submit без объяснения
- Ошибка в tooltip — не виден на мобильном, исчезает
- Зелёная галочка на каждом поле — становится визуальным шумом
- Reset формы после ошибки — пользователь убегает
outline: noneбез альтернативного focus
Полный UX-аудит сайта
Эвристическая оценка по Нильсену + проверка ключевых сценариев. На выходе — приоритизированный список проблем.
Микро-копирайтинг для форм: labels, ошибки, состояния
Точечный набор копий: labels, placeholders, hints, error messages, empty/success states. По одному примеру — пять разбора правил.
Конверсионный аудит формы регистрации
Карта трения по форме регистрации + 10 фиксов с ожидаемым импактом. Не «сделать красиво», а «убрать конкретное препятствие».