Формы — это ворота между пользователем и вашим сайтом. Если они кривые и глупые, посетитель уйдёт. Если умные и вежливые — останется и сделает заказ. Сегодня разберём, как сделать форму, которая сама проверяет данные, не перезагружая страницу, и подсказывает, что не так.
Зачем вообще нужна валидация на клиенте?
Представьте, что вы заполняете анкету на бумаге, а вам говорят: «Ошибка, перепишите всё заново». Бесит? Вот и пользователи злятся, когда форма отправляется, сервер думает три секунды и возвращает «неверный email». Клиентская валидация решает это мгновенно: пока вы печатаете, скрипт уже проверил поле и мягко намекнул, что что-то не так.
Плюсы очевидны: меньше нагрузки на сервер, быстрая обратная связь, удобство. Но есть и подводный камень: никогда не доверяйте только клиентской проверке. Злоумышленник может отключить JavaScript или отправить запрос напрямую. Поэтому серверная валидация обязательна, но клиентская — это ваш первый рубеж обороны и заботы о пользователе.
Скелет формы: HTML и немного CSS
Начнём с простого: форма регистрации с полями «Имя», «Email», «Пароль» и кнопкой. Никаких лишних украшательств, только необходимое.
<form id="signupForm" novalidate>
<div class="field">
<label for="name">Имя</label>
<input type="text" id="name" name="name" placeholder="Ваше имя">
<span class="error" id="nameError"></span>
</div>
<div class="field">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@example.com">
<span class="error" id="emailError"></span>
</div>
<div class="field">
<label for="password">Пароль</label>
<input type="password" id="password" name="password" placeholder="Минимум 6 символов">
<span class="error" id="passwordError"></span>
</div>
<button type="submit">Зарегистрироваться</button>
</form>
Атрибут novalidate отключает встроенную браузерную валидацию — она у нас будет своя, более гибкая. Каждое поле обёрнуто в div.field, а рядом с инпутом лежит span.error для вывода сообщения.
Добавим немного CSS, чтобы ошибки выглядели заметно, но не пугающе:
<style>
.field { margin-bottom: 1rem; }
.error { color: #d32f2f; font-size: 0.9rem; display: block; margin-top: 4px; }
input.invalid { border-color: #d32f2f; background-color: #fff6f6; }
input.valid { border-color: #2e7d32; }
</style>
Теперь поля при ошибке будут подсвечиваться красным, а при успехе — зелёным. Пользователь сразу видит, где косяк.
Пишем логику валидации на JavaScript
Основная идея: на каждое поле вешаем обработчик события input (или blur, чтобы проверять при уходе с поля). Функция валидации смотрит на значение и решает, пропускать или ругаться.
Начнём с простых проверок:
- Имя — не пустое, минимум 2 символа, только буквы и пробелы.
- Email — соответствует регулярному выражению (простая проверка на собаку и точку).
- Пароль — минимум 6 символов, хотя бы одна цифра и одна буква.
Вот функция, которая проверяет имя:
function validateName(value) {
if (value.trim() === '') {
return 'Имя не может быть пустым';
}
if (value.trim().length < 2) {
return 'Имя должно содержать минимум 2 символа';
}
if (!/^[a-zA-Zа-яА-Я\s]+$/.test(value)) {
return 'Имя может содержать только буквы и пробелы';
}
return ''; // пустая строка = ошибок нет
}
Аналогично для email и пароля. Для email используем простое регулярное выражение:
function validateEmail(value) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!re.test(value)) {
return 'Введите корректный email';
}
return '';
}
Пароль:
function validatePassword(value) {
if (value.length < 6) {
return 'Пароль должен быть не короче 6 символов';
}
if (!/\d/.test(value)) {
return 'Пароль должен содержать хотя бы одну цифру';
}
if (!/[a-zA-Z]/.test(value)) {
return 'Пароль должен содержать хотя бы одну букву';
}
return '';
}
Теперь нужно связать эти функции с полями. Напишем общий обработчик, который будет вызываться при вводе и при потере фокуса.
const form = document.getElementById('signupForm');
const nameInput = document.getElementById('name');
const emailInput = document.getElementById('email');
const passwordInput = document.getElementById('password');
const nameError = document.getElementById('nameError');
const emailError = document.getElementById('emailError');
const passwordError = document.getElementById('passwordError');
function showError(input, errorElement, message) {
if (message) {
input.classList.add('invalid');
input.classList.remove('valid');
errorElement.textContent = message;
} else {
input.classList.remove('invalid');
input.classList.add('valid');
errorElement.textContent = '';
}
}
function validateField(input, errorElement, validator) {
const message = validator(input.value);
showError(input, errorElement, message);
return message === '';
}
// Привязываем события
nameInput.addEventListener('input', () => {
validateField(nameInput, nameError, validateName);
});
emailInput.addEventListener('input', () => {
validateField(emailInput, emailError, validateEmail);
});
passwordInput.addEventListener('input', () => {
validateField(passwordInput, passwordError, validatePassword);
});
Теперь при каждом нажатии клавиши поле проверяется. Но это может быть навязчиво: пользователь ещё не допечатал email, а мы уже орём «неверный формат». Поэтому часто валидацию делают на событие blur (когда фокус уходит с поля). Можно комбинировать: первый раз проверяем на blur, а потом уже на input. Но для простоты оставим input — современные пользователи привыкли к мгновенной реакции.
blur или с задержкой (debounce) после ввода. Иначе вы будете ругаться на каждую букву.
Обработка отправки формы
Когда пользователь нажимает «Зарегистрироваться», нужно проверить все поля ещё раз. Если есть ошибки — не отправлять, показать сообщение. Если всё чисто — можно отправлять данные на сервер (через fetch или обычный submit).
form.addEventListener('submit', (event) => {
event.preventDefault(); // отменяем стандартную отправку
const isNameValid = validateField(nameInput, nameError, validateName);
const isEmailValid = validateField(emailInput, emailError, validateEmail);
const isPasswordValid = validateField(passwordInput, passwordError, validatePassword);
if (isNameValid && isEmailValid && isPasswordValid) {
// Все поля валидны — отправляем данные
const formData = new FormData(form);
console.log('Отправка:', Object.fromEntries(formData));
// Здесь можно сделать fetch('/api/register', { method: 'POST', body: formData })
alert('Форма успешно отправлена!');
} else {
// Подсвечиваем первое невалидное поле
if (!isNameValid) nameInput.focus();
else if (!isEmailValid) emailInput.focus();
else if (!isPasswordValid) passwordInput.focus();
}
});
Обратите внимание: мы вызываем event.preventDefault(), чтобы страница не перезагружалась. Это основа любой интерактивной формы.
Продвинутые приёмы и лайфхаки
Вот несколько фишек, которые сделают вашу форму ещё удобнее.
- Визуальная обратная связь. Добавьте иконки (галочка/крестик) или меняйте цвет рамки. Мы уже сделали через классы .valid и .invalid.
- Подсказки под полем. Вместо ошибки можно показывать требования к паролю заранее. Например, серым текстом: «Минимум 6 символов, хотя бы одна цифра».
- Блокировка кнопки. Если поля невалидны, кнопка отправки может быть неактивна (disabled). Но это спорно: пользователь может не понять, почему кнопка серая. Лучше оставить активной, но при клике показывать ошибки.
- Debounce. Если валидация тяжёлая (например, проверка занятости логина через AJAX), используйте задержку. Простая функция debounce:
function debounce(fn, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), delay);
};
}
И применяйте её к обработчику input: nameInput.addEventListener('input', debounce(() => validateField(...), 300));
Чтобы систематизировать знания, сведём основные параметры валидации в таблицу.
| Поле | Правило | Пример регулярного выражения |
|---|---|---|
| Имя | Только буквы и пробелы, от 2 символов | /^[a-zA-Zа-яА-Я\s]+$/ |
| Наличие @ и точки после неё | /^[^\s@]+@[^\s@]+\.[^\s@]+$/ |
|
| Пароль | Минимум 6 символов, цифра и буква | Проверка через /\d/ и /[a-zA-Z]/ |
aria-invalid и aria-describedby для доступности. Скринридеры будут читать ошибки вслух. Пример: input.setAttribute('aria-invalid', 'true'); и связать с span.error через aria-describedby.
И напоследок: не забывайте про серверную валидацию. Даже самая умная клиентская проверка обходится в два клика. Всегда дублируйте правила на бэкенде.
Что в итоге?
Мы сделали интерактивную форму с валидацией на чистом JavaScript. Теперь она:
- Мгновенно реагирует на ввод и показывает ошибки.
- Подсвечивает поля зелёным или красным.
- Не отправляется, пока все данные не корректны.
Главное — не переусердствовать. Валидация должна помогать, а не раздражать. Проверяйте на blur или с задержкой, пишите понятные сообщения об ошибках, и пользователи скажут спасибо. А если хотите глубже — изучайте библиотеки вроде Just-validate или Yup, но начинать всегда лучше с основ.
Студия WNDER



