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

Мне комфортнее не изобретать велосипед, а просто сглаживать кросс-браузерные несоответствия.

Но не изобретать велосипед очень сложно

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

Бинарной валидации недостаточно

Спецификации форм и вводимых данных предоставляют только 2 значения для статуса валидации: :valid и :invalid (валидно и невалидно). Это значение определяется только после того, как сработал onBlur, если только оно также не обозначено как :required (обязательно к заполнению), что при сабмите оценивается, как :invalid.
Хотя, это не всегда правда.

“Пустая строка означает, что ограничение удовлетворено”.

4ZkLAI9iap

MDN: Валидация ограничения

Я встречал, как ребята вроде @joshblack используют объекты вроде Enum с 4 состояниями, что кажется гораздо лучшей идеей.

'valid' | 'invalid' | 'validating' | 'initial';

У нас есть псевдоклассы CSS :out-of-range для диапазонов минимум-максимум и :indeterminate для полузаполненных чекбоксов, но не разбивка псевдо-классов по валидности исходных состояний.

DOM-валидация API

Метод DOM event.target.validity доступен только для чтения, не изменяем, так как это метод ValidityState. И это досадно, потому что можно было бы извлечь из них супер-пользу.

Вы также можете только считывать и из checkValidity() ~~ Не существует программного способа в браузере, чтобы принудительно настроить валидность поля ~~. Обновление: Я был не прав насчет этого. Вот как вы можете заставить браузер применить :valid и :invalid на собственных условиях.

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

Любое ненулевое значение, передаваемое как параметр в setCustomValidity( )применяет псевдокласс CSS :invalid. field.setCustomValidity(«Это поле не может быть пустым»);

Чтобы восстановить псевдо-класс CSS :valid, передайте пустую строку в setCustomValidity().field.setCustomValidity(«»);

Помните, что это API не поддерживается всеми браузерами.

Еще одно любопытное свойство — HTMLInputElement.validationMessage. Это еще один параметр только для чтения, он появляется при ховере на невалидный элемент.

UZG1ZFza4W

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

S2RW9E0lSK

«Нет стандартного способа изменить их вид средствами CSS”.

MDN — Валидация форм данных

Конечно, вы можете поиграть с классами вроде .invalid, .required и т.д., но я могу вас убедить: это верный путь к сумасшествию.

А что по доступности?

Все вышеперечисленное в крайней степени недоступно. Так как для того, чтобы сделать ввод данных комфортным, безболезненным процессом, работающим стабильно в разных контекстах, все-таки придется изобрести велосипед, мы сломали все родные возможности HTML. Разработчики вынуждены применять атрибуты вроде aria-live, а проектировщики — рвать на себе волосы.

Мы поступим иначе.

Более умные параметры по умолчанию

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

  • Автоматическое отключение автокорректировки, автокапитализации, на полях email, url, password и прочих типах ввода, которые не являются текстом или поиском.
  1. Используйте плейсхолдеры, переделав их в статические маски ввода.CmP59mFEAT
  2. Улучшите регулярные выражения для валидации имейлов. (https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address)
     /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/

    позволяет следующее:

fy_ngYVsw2

Погуглите 5 лишних секунд, и вы найдете регулярное выражение получше, вроде этого. [a-zA-Z0-9_]+(?:\.[A-Za-z0-9!#$%&’*+/=?^_`{|}~-]+)*@(?!([a-zA-Z0-9]*\.[a-zA-Z0-9]*\.[a-zA-Z0-9]*\.))(?:[A-Za-z0-9](?:[a-zA-Z0-9-]*[A-Za-z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?

  1. Улучшение маскировки паролей. Как минимум, добавьте возможность скрыть пароль в UI.
    • Используйте тот же тип ввода данных для капчи.
    • Добавьте input type=»fingerprint». Родные мобильные ОС уже так делают.
  2. Используйте UI-аналоги в Вебе для полей ввода из родных мобильных интерфейсов
    • Тогглы — бинарные переключатели со значениями on/off.
    • Сегментированные средства управления. Возможно, тип радиокнопки или кнопки выбора.
    • Тип ввода “геолокация”. У нас уже есть геолокационные API. Почему бы не стандартизировать ввод? Атрибуты шага позволяют наладить более точное управление.
    • Используйте стандартные CSS-формы с мобильно-ориентированной стилизацией
    • Большие, разделенные области касания
    • Меню выбора вместо отдельных полей ввода для месяца, дня, времени и т.д.
  3. Временные данные могут быть лучше
    • Представьте типы даты рождения, которые автоматически определяют диапазон возраста с максимально до минимально приемлемого в соответствии с требованиями ресурса, чтобы не пришлось переспрашивать: “А вы действительно из будущего?”.
  • Задайте постоянное относительное время и дату для вводимых значение времени и элементов. Хороший пример подходящего API найдете в moment.js.
  1. Дайте валидационным API больше контроля и меньше шаблонности, когда дело касается кастомной валидации на стороне клиента.
    • Определите ошибки валидации как атрибуты на элементах ввода
    • Добавьте опцию задания кастомных сообщений об ошибке для каждого ValidityState, включая произвольные.
  2. Позвольте разработчику выбрать, когда нужна валидация
    • По умолчанию встроенная валидация происходит с 2 секундной задержкой и/или onBlur()
  3. Предусмотрите возможность перекрывать CSS для поп-оверов с сообщениями об ошибках валидации в браузере.
  4. Используйте ввод с камеры и микрофона, чтобы упростить ввод речи и медиа-контента.
  5. Четко отделяйте значение и добавляйте initialValue (изучите React.js’s defaultValue attribute, чтобы понять, зачем). TL;DR: проверяйте, что происходит, когда вы задаете начальное значение для ввода, который не соответствует паттерну.

Избегайте путаницы при использовании таких сценариев: <input type=text inputmode=numeric>(triggers numeric software keyboard) vs. <input type=»number»> (не включает программную цифровую клавиатуру).

  • <input type=»number»>автоматически должен иметь inputmode=»numeric» и pattern=»[0-9]*»
  1. Не нужно, чтобы элементы ввода были обязательно обернуты элементами меток, чтобы охватить большую площадь касания. Доступность: ДА! Поломка разметки: НЕТ!
  2. <input type=»emoji»> — это имеет смысл только в разрезе появления большого количества реакционных интерфейсов.
  3. Не бойтесь кастомных клавиатур. Конечно, это выглядит страшно, и много опасностей подстерегают вас. Все, что я прошу, просто рассмотрите их. Они дают и множество полезных возможностей.

Как вы говорите, W3C?

Это только некоторые улучшения и предложения для повышения комфорта пользователей и разработчиков. Давайте внедрим их в жизнь.