Валидация полей: pattern, accept, ValidityState и другие

Существуют различные сторонние библиотеки, которые помогают настраивать валидацию форм на сайте, но есть и простые способы сделать это самостоятельно, например, используя встроенные атрибуты для полей ввода. Они позволяют нативно совершать несложную проверку вводимых пользователем данных в браузере перед тем, как отправить их на сервер.

На стороне клиента применяется в основном два вида валидации:

  • При отправке формы. Это происходит путем нажатия на соответствующую кнопку на сайте или клавишу Enter. Настройку можно осуществить, используя встроенные атрибуты без скриптов.

  • При потере фокуса. Такая валидация полностью настраивается JavaScript’ом.

Валидация с помощью атрибутов имеет большой плюс: она будет работать, даже если у пользователя отключен JavaScript. Такой способ отлично подходит для каких-либо небольших форм, чтобы не тянуть за собой дополнительные скрипты. Но все же удобней будет проводить проверку не только тогда, когда пользователь заполнит все поля и решит отправить данные, но и как можно раньше (при потери фокуса с элемента).

В этой статье мы разберем несколько примеров настройки валидации в браузере.

Почему важно проводить валидацию?

Прежде, чем пользователь отправит данные, необходимо убедиться, что они попадут на сервер в том виде, в каком ожидаются. Поле с номером телефона должно действительно содержать номер телефона в требуемом формате, и ни в коем случае не буквы.

В идеале, чтобы у пользователя на сайте не возникало сомнений, что именно и в каком виде нужно вводить. Например, может быть placeholder у текстовых полей, или подсказка при наведении на элемент. Сообщения об ошибках тоже должны быть понятны посетителю.

Очень важным моментом является то, что данные которые отправляются, способны нести угрозу для сервера от злоумышленников, ботов и особо продвинутых пользователей, которые могут обойти валидацию в браузере через консоль или даже адресную строку. Чтобы избежать этого, валидация обязательно должна быть и на стороне клиента и на стороне сервера.

Валидация с помощью атрибутов

required

Устанавливает элемент обязательным для заполнения. Отправка формы не осуществится, если данное поле будет пустым, и пользователю будет предоставлено сообщение о том, что оно является обязательным.

Это очень часто используемый атрибут. Работает также со всеми элементами формы, кроме <input type="image"> и любых видов кнопок (submit, reset, button).

maxlength

Атрибут maxlength устанавливает максимальное количество символов, которое может быть введено в текстовом поле. Никакого предупреждения браузер не выдаст, если это количество будет достигнуто — лишь станет невозможным дальнейший ввод.

Пример:

<form>
  <input type="text" name="about" maxlength="100">
</form>

max

Задает максимальное значение для поля с типом range.

min

Задает минимальное значение для поля с типом range.

accept

Атрибут accept используется только для <input type="file">. Он принимает MIME-тип доступных для выбора файлов.

По сути, здесь и не происходит никакой проверки на соответсвтвие выбранного пользователем файла с тем форматом, который мы от него ожидаем — браузер просто не разрешит выбрать что-либо кроме того, что будет передано в accept.

Примеры:

  • accept="image/png, image/jpeg" или accept=".png, .jpeg" — позволяет загружать только png и jpeg картинки.

  • accept="image/*" — принимает любой формат изображений.

  • accept=".xlsx,.xls,.doc,.docx,.ppt,.pptx,.txt,.pdf" — принимает файлы расширений из указанного перечня.

pattern

На этом атрибуте хотелось бы сделать бо́льший акцент, т.к. именно он является основным для настройки валидации.

pattern принимает регулярное выражение. В момент отправки формы (но до события submit), введенные пользователем данные будут подвержены проверке. В случае несоответствия, отобразится сообщение об ошибке, иначе — осуществится отправка формы.

У полей ввода <input> имеется множество типов: email, tel, text, search, url и т.д. Но не ко всем применим атрибут pattern.

Например, этот атрибут работает для <input type="password"> (странно, конечно), но его использование в данном случае абсурдно, ведь для ввода пароля не может быть никаких ограничений. Для <input type="file"> вместо него существует accept. А для <textarea> атрибут pattern недоступен, хотя этот тэг нам также представляется как текстовое поле. У него нет аналогичного атрибута.

Простой пример валидации поля для номера телефона:

<form>
  <input type="tel" name="phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" required>
  <span class="note">Формат: 987-654-3210</span>
</form>

Простой пример валидации поля для времени:

<form>
  <input type="text" name="time" pattern="^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$" required>
  <span class="note">Формат: 10:15</span>
</form>

Простой пример валидации ника пользователя:

<form>
  <input type="text" name="username" pattern="[a-zA-Z]{2,15}" required>
  <span class="note">Имя может содержать латинские буквы длиной от 2 до 15</span>
</form>

Простой пример поля “только для чисел”:

<form>
  <input type="text" name="age" pattern="[0-9]+" required>
  <span class="note">Укажите возраст</span>
</form>

В результате получаем, что если пользователь введет данные в некорректном формате и попытается отправить форму, то браузер выдаст соответствующее системное сообщение с предупреждением. Для каждого браузера оно выглядит по-разному:

  • Chrome: «Введите данные в указанном формате».

  • Safari: «Подберите запрошенный формат».

  • Firefox: «‎‎Пожалуйста, используйте требуемый формат».

  • Opera: «Введите данные в указанном формате».

  • IE: «Необходимо использовать этот формат».

  • Edge: «Необходимо использовать этот формат».

Как можно заметить, системные сообщения не полностью отражают необходимую для пользователя информацию, и некоторые моменты остаются неясны. Допустим, вместо абстрактной фразы «Введите данные в указанном формате» нам хотелось бы видеть подсказку, чтобы иметь представление, какие символы можно вводить, а какие нельзя. Ведь pattern не запрещает ввод недопустимых символов, а лишь отвечает за их проверку. Мы с легкостью можем заменить стандартное системное сообщение на свое собственное, но уже с помощью JavaScript класса ValidityState (ниже будет пример).

ValidityState

С помощью JavaScript класса ValidityState можно отслеживать состояния валидности любого элемента формы.

Браузеры спокойно поддерживают API валидации для следующих элементов:

Основные свойства:

СвойствоОписание
validityСам объект ValidityState. В нем описываются состояния элемента
validity.customErrorЕсли элемент содержит кастомную ошибку, возвращает true, иначе — false
validity.patternMismatchЕсли значение элемента не соответствует заданному шаблону, возвращает true, иначе — false
validity.rangeOverflowЕсли значение элемента выше заданного максимума, возвращает true, иначе — false
validity.rangeUnderflowЕсли значение элемента ниже заданного минимума, возвращает true, иначе — false
validity.stepMismatchЕсли значение элемента не удовлетворяет правилам, заданным с помощью атрибута step, возвращает true, иначе — false
validity.tooLongЕсли значение элемента больше заданной длины, возвращает true, иначе — false
validity.typeMismatchЕсли значение элемента имеет некорректный синтаксис, возвращает true, иначе — false
validity.validЕсли значение элемента не имеет никаких проблем с валидностью, возвращает true, иначе — false
validity.valueMissingЕсли элемент является обязательным (имеет атрибут required), но не заполнен, возвращает true, иначе — false
willValidateЕсли элемент будет проверен при отправке формы, возвращает true, иначе — false
validationMessageСвойство, задающее сообщение, которое описывает ограничение валидности. Может иметь пустую строку, если willValidate = false

API методы:

МетодОписание
checkValidity()Возвращает true, если значение элемента не имеет проблем с валидностью, иначе — false
HTMLFormElement.reportValidity()Возвращает true, если элемент и его дочерние элементы удовлетворяют требуемым ограничениям. Когда возвращается false, вызывается отменяемое событие invalid для каждого из некорректно введенных элементов; пользователю приходит сообщение о проблеме
setCustomValidity(message)Задает элементу пользовательское сообщение об ошибке. Если какое-либо сообщение задано, то элемент переходит в состояние invalid. Если аргумент является пустой строкой, то пользовательская ошибка очищается.

Кастомное сообщение

Возьмем следующий пример. В форме имеется поле для ввода имени пользователя, которое может состоять только из латинских букв длиной от 2 до 15 символов, и нам необходимо поменять текст системного сообщения:

<form>
  <span class="note">Имя пользователя:</span>
  <input id="username" type="text" name="username" pattern="[a-zA-Z]{2,15}" required>
</form>

В JavaScript обратимся к текстовому полю по id и с помощью свойства setCustomValidity зададим необходимый текст сообщения:

let username = document.getElementById('username');

username.addEventListener('input', () => {
  if (username.validity.typeMismatch) {
    username.setCustomValidity('Имя пользователя может содержать только латинские буквы длиной от 2 до 15');
  } else {
    username.setCustomValidity('');
  }
});

Вот таким простым способом можно поменять текст с предупреждением, теперь пользователю станет понятней, почему произошла ошибка, ведь подсказка полностью отражает, какие символы допустимы для использования.

Валидация при потере фокуса с элемента

Скриптами можно дополнить функционал валидации и сделать его более удобным для пользователя. Например, есть способ уведомлять об ошибке как можно раньше — мгновенно, при непосредственном вводе данных, но тут возникает ситуация: в тот момент, как пользователь только начинает вводить текст, поле уже сигналит о несоответствии требуемому формату (что выглядит немного неприятно, ведь человек еще даже не успел ввести то, что хотел).

Самым лучшим вариантом будет: проверять корректность введенных данных при потере фокуса с элемента. То есть, пользователь заполняет поле, в случае несоответствия с ожидаемым форматом, выводится сообщение об ошибке, человек ее исправляет и шаг за шагом переходит к оставшимся элементам. Такой сценарий валидации встречается достаточно часто. Давайте попробуем сделать этот пример.

Нам также потребуется использовать встроенные атрибуты: pattern, required (ValidityState работает на основе их наличия и содержимого). Создадим следующую форму:

<form>
  <div class="field">
    <span class="label">Имя</span>
    <input id="username" type="text" name="username" pattern="[a-zA-Z]{2,15}" required>
    <span class="message">Имя пользователя может содержать только латинские буквы (2-15 символов)</span>
  </div>
  <div class="field">
    <span class="label">Возраст</span>
    <input id="age" type="text" name="age" pattern="[0-9]{1,2}" required>
    <span class="message">Введите настоящий возраст</span>
  </div>
  <div class="field">
    <span class="label">Почта</span>
    <input id="email" type="text" name="email" pattern="[a-zA-Z0-9-_а-яА-ЯёЁ.]+@[a-zA-Z0-9-_а-яА-ЯёЁ]+\.[a-zA-Zа-яА-ЯёЁ]+" required>
    <span class="message">Введите почту в формате qwe@qwe.qwe</span>
  </div>
  <button type="submit">Отправить</button>
</form>

Стили для нее:

.field {
  margin: 10px 0;
}

.field input {
  border-radius: 3px;
  border: solid 1px #000;
}

.field.error input {
  outline: solid 1px red;
}

.field .message {
  display: none;
}

.field.error .message {
  display: inline-block;
  color: red;
}

Форма в браузере будет выглядеть примерно так:

валидация форм

По умолчанию span является скрытым. Он будет служить для вывода текста сообщения об ошибке.

Далее с помощью JavaScript в цикле находим все <input> и вешаем для каждого обработчик на событие change. В этом обработчике у текущего элемента (event.target) ищем родителя с классом field. Ему мы будем добавлять класс error при условии, когда у поля состояние будет validity.valid === false. Класс error отвечает за отображение сообщения об ошибке и красную обводку для <input>.

Получивщийся код:

document.querySelectorAll('input').forEach((input) => {
  input.addEventListener('change', (event) => {
    event.target.closest('.field').classList.toggle('error', !event.target.validity.valid);
  });
});

В результате, когда пользователь вводит недопустимые данные и пытается перейти к следующему полю, появляется сообщение об ошибке, которое не пропадет до тех пор, пока данные не будут введены в необходимом формате:

валидация форм

Как видите, настройка валидации полей формы не требует сложных JavaScript манипуляций, а вполне доступна и легка в освоении. Тем более ее можно настроить даже без использования скриптов. А поддержка осуществлена во всех современных браузерах.

Но не забывайте, что надеяться на проверку только на стороне браузера нельзя, т.к. она легко обходится, поэтому обязательно должна быть дополнительная валидация на сервере.