Валидация форм в JavaScript
Два уровня проверки
Браузер умеет проверять поля до отправки на сервер:
- HTML —
required,minlength,type="email",pattern,min/max(см. HTML-теги и формы). - JavaScript — Constraint Validation API: читать состояние поля, показывать свои сообщения, блокировать
submit.
Серверная проверка остаётся обязательной: клиентский код можно обойти.
Связь: события форм, работа с DOM, регулярные выражения для сложных pattern, чтение и загрузка файлов.
Объект validity
У каждого поля формы (HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement) есть свойство validity — набор флагов, почему значение не прошло проверку:
| Свойство | Когда true |
|---|---|
valueMissing | пустое обязательное поле |
typeMismatch | не подходит type (email, url…) |
patternMismatch | не совпало с pattern |
tooShort / tooLong | длина вне minlength / maxlength |
rangeUnderflow / rangeOverflow | число или дата вне min / max |
stepMismatch | не кратно step |
badInput | браузер не может прочитать значение |
customError | вы вызвали setCustomValidity с непустой строкой |
valid | все проверки пройдены |
const email = document.querySelector('#email');
email.addEventListener('input', () => {
if (email.validity.typeMismatch) {
console.log('Нужен адрес вида user@example.com');
}
});
Основные методы
checkValidity()
Возвращает true, если поле (или форма) валидно. Не показывает встроенный «пузырь» браузера.
if (!form.checkValidity()) {
// подсветить ошибки своим UI
}
reportValidity()
Как checkValidity, но при false браузер показывает стандартное сообщение у первого невалидного поля (если не отключено CSS).
form.addEventListener('submit', (event) => {
if (!form.reportValidity()) {
event.preventDefault();
}
});
setCustomValidity(message)
Задаёт свою причину ошибки. Пустая строка '' снимает customError.
const password = document.querySelector('#password');
const confirm = document.querySelector('#confirm');
function validatePair() {
if (confirm.value && confirm.value !== password.value) {
confirm.setCustomValidity('Пароли не совпадают');
} else {
confirm.setCustomValidity('');
}
}
password.addEventListener('input', validatePair);
confirm.addEventListener('input', validatePair);
Правило: после каждого изменения, влияющего на правило, снова вызывайте setCustomValidity('') или с новым текстом.
События
| Событие | Когда |
|---|---|
invalid | поле не прошло проверку при submit (можно preventDefault на кастомный UI) |
input | значение меняется — удобно снимать ошибку «на лету» |
change | значение зафиксировано (select, checkbox после выбора) |
field.addEventListener('invalid', (event) => {
event.preventDefault(); // отключить стандартный bubble
showError(field, field.validationMessage);
});
validationMessage — текст, который показал бы браузер (учитывает setCustomValidity).
Связка с CSS
В псевдоклассах CSS используют :user-invalid / :invalid для подсветки:
input:user-invalid {
border-color: #c0392b;
outline: 2px solid rgba(192, 57, 43, 0.3);
}
:user-invalid срабатывает после взаимодействия пользователя — меньше «красных полей» при первой загрузке страницы.
Пример — форма с единым блоком ошибок
<form id="signup" novalidate>
<!-- novalidate — только наш или смешанный сценарий; иначе двойные сообщения -->
<label>
Логин
<input name="login" required minlength="3" id="login">
</label>
<p id="login-error" hidden></p>
<button type="submit">Создать</button>
</form>
const form = document.getElementById('signup');
const login = document.getElementById('login');
const loginError = document.getElementById('login-error');
login.addEventListener('input', () => {
login.setCustomValidity('');
loginError.hidden = true;
});
form.addEventListener('submit', (event) => {
if (!form.checkValidity()) {
event.preventDefault();
if (!login.validity.valid) {
loginError.textContent = login.validationMessage;
loginError.hidden = false;
login.focus();
}
return;
}
// отправка fetch или form.submit() на сервер
});
Атрибут novalidate на <form> отключает встроенный UI браузера — полезно, если сообщения рисуете вы сами. Без него можно вызывать reportValidity() точечно.
Асинхронная проверка (логин занят)
Встроенный API синхронный. Проверка «логин свободен на сервере» делается так:
- На
submit—preventDefault. fetchна API.- При конфликте —
field.setCustomValidity('Логин занят')иfield.reportValidity(). - При успехе —
form.requestSubmit()или отправка данных.
Не вызывайте setCustomValidity с текстом до ответа сервера на каждый input без debounce — иначе лишние запросы.
Отправка данных — FormData
После успешной проверки форму обычно отправляют на сервер. FormData собирает пары «имя поля → значение» из разметки, в том числе файлы:
const form = document.getElementById('signup');
form.addEventListener('submit', async (event) => {
event.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const body = new FormData(form);
// Дополнительные поля, которых нет в HTML:
body.append('source', 'web');
const response = await fetch('/api/signup', {
method: 'POST',
body, // Content-Type с boundary выставит браузер сам
});
if (!response.ok) throw new Error('Ошибка сервера');
const data = await response.json();
console.log('Создан пользователь', data.id);
});
Полезные методы:
| Метод | Назначение |
|---|---|
new FormData(form) | Снимок всех полей формы с атрибутом name |
append(name, value) | Добавить или продублировать ключ |
get(name) / getAll(name) | Прочитать одно или все значения |
delete(name) | Убрать ключ перед отправкой |
entries() | Итерация для отладки или ручной сборки |
Файлы: <input type="file" name="avatar"> попадает в FormData как File. Несколько файлов — getAll('avatar').
Если API ждёт JSON, а не multipart, соберите объект вручную:
const payload = Object.fromEntries(new FormData(form));
await fetch('/api/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
Для JSON файлы не сериализуются — для загрузки файлов оставляйте FormData или отдельный fetch с Blob. Отмена долгой отправки — AbortController; разбор ответа — в асинхронном программировании.
Практические правила
- Дублируйте критичные правила на сервере.
- Сообщения — рядом с полем, связь
label+id, для скринридеров —aria-invalid="true"иaria-describedbyна блок ошибки. - Не валидируйте скрытые поля (
display: none) так же, как видимые — пользователь не может исправить. - Для масок (телефон) —
inputmode,patternили маска в JS; регулярные выражения — дляpattern, не для всей логики формы.
Краткий итог
Constraint Validation API связывает HTML-атрибуты и скрипт: validity, checkValidity, setCustomValidity, reportValidity. Начните с нативных атрибутов, добавьте JS для парных полей и серверных правил, оформите ошибки через CSS и доступную разметку.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Основы JavaScript - стандарт ECMAScript, модель выполнения и базовые конструкции языка. JavaScript — это язык программирования, который позволяет создавать интерактивные веб-страницы, серверные приложения и мобильные программы. Для создания массивов используется литеральная нотация. Конструктор Array не применяется. Как работать с HTML-элементами, как их создавать, менять. Простые приложения на JavaScript - базовые сценарии, структура кода и быстрый старт с практическими примерами. Расширения файлов определяют способ обработки кода средой выполнения или компилятором. История JavaScript - происхождение языка, ключевые этапы развития и влияние на современный веб. Такое именование представляет собой соглашение между разработчиками. Классический JavaScript не обеспечивает реальной приватности через подчеркивания. JavaScript содержит набор зарезервированных слов, которые имеют специальное значение в языке. Эти слова нельзя использовать в качестве идентификаторов для переменных, функций или классов. Встроенные функции JavaScript - ключевые методы массивов, строк и объектов для повседневной разработки. Этот шаблон описывает подключение внешних функций, классов или значений из других файлов. Он используется в начале файла и определяет зависимости текущего модуля. JavaScript используется для создания кроссплатформенных мобильных приложений, которые работают на iOS и Android с использованием единой кодовой базы.Основы JavaScript
Что требуется знать перед началом изучения языка программирования JavaScript
Рекомендации по разработке на JavaScript
Работа с HTML в JavaScript
Простые приложения на JavaScript
Форматы JavaScript
История языка JavaScript
Синтаксис и пунктуация в JavaScript
Ключевые слова языка JavaScript
Встроенные функции JavaScript
Структура и подключение JavaScript-кода
Применение JavaScript в вебе и за его пределами