Кастомная валидация форм
Кастомная валидация форм — проверка данных, введённых пользователем, средствами JavaScript с формированием понятных сообщений об ошибках и управлением состоянием полей, в дополнение к встроенной HTML5-валидации или вместо неё.
Зачем нужно
Встроенная HTML5-валидация (required, pattern, min/max) ограничена в кастомизации внешнего вида и не поддерживает сложные правила (совпадение паролей, уникальность email через API). Кастомная валидация на JS даёт полный контроль над UX: когда показывать ошибку, как её оформить, как проверить данные.
Где используется
- Формы регистрации и авторизации
- Многошаговые формы (wizard)
- Валидация в реальном времени (при вводе / на blur)
- Комплексные правила: зависимые поля, async-проверки
Примеры
Базовая валидация поля
function validateEmail(value) {
if (!value) return 'Email обязателен';
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Неверный формат email';
return null; // null = валидно
}
function showError(input, message) {
const field = input.closest('.form-field');
const errorEl = field.querySelector('.error-message');
input.classList.toggle('input--error', Boolean(message));
errorEl.textContent = message || '';
errorEl.hidden = !message;
}
const emailInput = document.getElementById('email');
emailInput.addEventListener('blur', () => {
const error = validateEmail(emailInput.value);
showError(emailInput, error);
});
Валидация всей формы перед отправкой
const validators = {
name: (v) => !v.trim() ? 'Имя обязательно' : null,
email: (v) => !v.includes('@') ? 'Неверный email' : null,
password: (v) => v.length < 8 ? 'Минимум 8 символов' : null,
confirm: (v, form) =>
v !== form.password.value ? 'Пароли не совпадают' : null,
};
document.getElementById('register-form').addEventListener('submit', (event) => {
event.preventDefault();
const form = event.target;
let isValid = true;
Object.entries(validators).forEach(([fieldName, validate]) => {
const input = form[fieldName];
const error = validate(input.value, form);
showError(input, error);
if (error) isValid = false;
});
if (isValid) submitForm(new FormData(form));
});
Валидация в реальном времени с debounce
const debounce = (fn, ms) => {
let t;
return (...args) => { clearTimeout(t); t = setTimeout( => fn(...args), ms); };
};
const usernameInput = document.getElementById('username');
const checkUsername = debounce(async (value) => {
if (!value) return showError(usernameInput, 'Обязательное поле');
showLoading(usernameInput, true);
const res = await fetch(`/api/check-username?q=${value}`);
const { available } = await res.json();
showLoading(usernameInput, false);
showError(usernameInput, available ? null : 'Имя уже занято');
}, 400);
usernameInput.addEventListener('input', (e) => checkUsername(e.target.value));
Constraint Validation API
// Встроенный API для кастомных сообщений
const input = document.getElementById('phone');
input.addEventListener('input', () => {
const isValid = /^\+7\d{10}$/.test(input.value);
input.setCustomValidity(isValid ? '' : 'Формат: +79991234567');
input.reportValidity;
});
Частые ошибки
- Валидация только на клиенте — всегда дублируйте валидацию на сервере; клиентская — только UX.
- Показывать ошибку сразу при фокусе — лучше показывать ошибку при
blur(потере фокуса) или отправке, а не при первом символе. - Не блокировать отправку при ошибках — всегда вызывайте
event.preventDefault()и проверяйте все поля передsubmitForm.
Связанные темы
- _MOC DOM
- _MOC JavaScript
- preventDefault и stopPropagation
- data-атрибуты (dataset)
- classList -- add, remove, toggle, contains