HTML5 валидация

HTML5 валидация основана на встроенном механизме проверки ограничений (Constraint Validation API), который применяется к стандартным элементам форм: input, select, textarea. При использовании кастомных UI-компонентов, таких как Slim Select, базовое поведение нативного <select> часто скрывается, но логика валидации продолжает опираться на исходный DOM-элемент.

Slim Select не заменяет HTML-элемент <select>, а оборачивает его и управляет отображением. Это означает, что вся HTML5-валидация остаётся доступной, однако требует правильной синхронизации состояния между UI и оригинальным элементом формы.


Базовый механизм валидации в связке со Slim Select

HTML5 валидирует именно <select>, даже если визуально используется Slim Select. Ключевыми атрибутами являются:

  • required
  • multiple
  • disabled
  • name
  • value

Пример базовой разметки:

<form id="form">
  <select id="country" required>
    <option value="">Выберите страну</option>
    <option value="kz">Kazakhstan</option>
    <option value="ru">Russia</option>
    <option value="de">Germany</option>
  </select>

  <button type="submit">Отправить</button>
</form>

Инициализация Slim Select:

new SlimSelect({
  select: '#country'
});

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


Поведение required в Slim Select

Атрибут required активирует проверку на пустое значение. Для <select> пустым считается:

  • "" (пустая строка)
  • отсутствие выбранной опции
  • placeholder-значение, если оно не исключено из выбора

Slim Select синхронизирует выбранное значение с оригинальным <select>, поэтому HTML5-валидация работает автоматически при условии, что:

  • значение placeholder имеет value=""
  • пользовательский выбор обновляет select.value

Валидация при множественном выборе

При использовании multiple логика проверки меняется: валидным считается наличие хотя бы одного выбранного значения.

<select id="tags" multiple required>
  <option value="js">JavaScript</option>
  <option value="css">CSS</option>
  <option value="html">HTML</option>
</select>

Slim Select поддерживает множественный выбор через массив значений, который синхронизируется с DOM:

new SlimSelect({
  select: '#tags'
});

В этом случае HTML5 проверяет:

  • select.value.length > 0
  • либо наличие выбранных option[selected]

Проблема кастомных placeholder-значений

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

Правильная конфигурация:

<option value="" disabled selected hidden>Выберите значение</option>

Такой вариант гарантирует:

  • значение пустое ("")
  • required остаётся активным
  • браузер корректно блокирует отправку формы

Программное управление валидностью через setCustomValidity

HTML5 предоставляет механизм ручного управления состоянием ошибки через setCustomValidity.

Это особенно важно при использовании Slim Select, когда стандартной проверки недостаточно (например, бизнес-логика).

const select = document.querySelector('#country');

select.addEventListener('change', () => {
  if (select.value === 'kz') {
    select.setCustomValidity('');
  } else {
    select.setCustomValidity('Разрешён выбор только Казахстана');
  }
});

Slim Select не блокирует этот механизм, так как он работает на уровне оригинального <select>.


Отображение ошибок и reportValidity

Метод reportValidity() инициирует показ стандартного браузерного сообщения об ошибке.

const form = document.querySelector('#form');
const select = document.querySelector('#country');

form.addEventListener('submit', (e) => {
  if (!select.checkValidity()) {
    e.preventDefault();
    select.reportValidity();
  }
});

Slim Select не перехватывает этот вызов, однако визуальная часть ошибки отображается не на кастомном элементе, а на нативном <select>, который может быть скрыт стилями.


Проблема скрытого select и UX-ограничения

При использовании Slim Select оригинальный <select> часто скрывается через CSS:

select {
  display: none;
}

Это создаёт ситуацию:

  • HTML5-валидация работает
  • сообщение об ошибке появляется, но не всегда визуально привязано к UI Slim Select
  • пользователь не видит подсветку кастомного компонента

Из-за этого требуется дополнительная синхронизация состояния ошибки с UI Slim Select.


Синхронизация состояния ошибки со Slim Select

Для улучшения UX часто используется ручное управление классами состояния.

Пример логики:

const select = document.querySelector('#country');
const wrapper = select.nextElementSibling;

function updateErrorState() {
  if (select.validity.valid) {
    wrapper.classList.remove('is-error');
  } else {
    wrapper.classList.add('is-error');
  }
}

select.addEventListener('change', updateErrorState);

CSS:

.is-error {
  border: 1px solid red;
}

Таким образом визуальная ошибка переносится с нативного элемента на кастомный интерфейс Slim Select.


Использование validity API

Объект validity предоставляет детализированное состояние ошибки:

  • valueMissing
  • typeMismatch
  • patternMismatch
  • tooShort
  • tooLong
  • customError

Пример обработки:

select.addEventListener('invalid', (e) => {
  if (select.validity.valueMissing) {
    select.setCustomValidity('Поле обязательно для заполнения');
  }
});

Валидация при динамическом изменении опций

Slim Select часто используется с динамической загрузкой данных. В таких сценариях важно учитывать пересчёт валидности после обновления списка:

function updateOptions(data) {
  const select = document.querySelector('#country');

  select.innerHTML = '';

  data.forEach(item => {
    const option = document.createElement('option');
    option.value = item.code;
    option.textContent = item.name;
    select.appendChild(option);
  });

  select.dispatchEvent(new Event('change'));
}

HTML5-валидация пересчитывается автоматически при изменении DOM, но Slim Select должен быть синхронизирован с обновлённым состоянием.


Поведение при reset формы

Метод form.reset() возвращает <select> к начальному состоянию. Slim Select при этом может не обновить UI автоматически, если не вызвана синхронизация.

form.addEventListener('reset', () => {
  setTimeout(() => {
    select.dispatchEvent(new Event('change'));
  });
});

Это важно для восстановления:

  • placeholder-состояния
  • required-валидации
  • визуального состояния Slim Select

Особенности совместимости с браузерной валидацией

HTML5-валидация в Slim Select сохраняет поведение:

  • Chrome и Edge полностью поддерживают Constraint Validation API
  • Firefox корректно обрабатывает setCustomValidity
  • Safari может по-разному отображать сообщения при скрытых <select>

Основная проблема заключается не в логике, а в визуальном отображении ошибок при кастомном UI.


Поведение при disabled состоянии

Если <select disabled>:

  • HTML5-валидация игнорирует поле
  • Slim Select отключает интерактивность UI
  • значение не отправляется в форму
<select id="country" disabled>

Валидация и программное изменение value

При установке значения программно:

select.value = 'kz';
select.dispatchEvent(new Event('change'));

Slim Select обновляет UI, но HTML5-валидация пересчитывается только при проверке формы или вызове checkValidity().


Роль Slim Select в контексте HTML5 validation flow

Slim Select выступает как слой представления, не вмешиваясь в:

  • Constraint Validation API
  • submit-поведение формы
  • native validity state

Однако он требует ручной синхронизации для:

  • визуального отображения ошибок
  • кастомных сообщений
  • динамических изменений состояния формы

Это делает интеграцию не полностью автоматической, но предсказуемой при соблюдении принципа: источник истины всегда остаётся за оригинальным <select>.