Интеграция с валидацией форм

Slim Sel ect используется как надстройка над стандартным <select>-элементом, при этом сохраняется его семантика и интеграция с формами HTML. Это позволяет сочетать кастомный UI выбора значений с нативной системой валидации браузера, включая required, pattern, minlength и Constraint Validation API.

При подключении Slim Select DOM-элемент не заменяется логически: исходный <select> остаётся частью формы, а библиотека лишь синхронизирует визуальное состояние. Именно это свойство делает возможной прозрачную интеграцию с механизмами проверки данных.


Обычный <select> после инициализации Slim Select продолжает участвовать в отправке формы и проверке валидности. Значение обновляется через синхронизацию состояния компонента и DOM-узла.

Ключевой аспект заключается в том, что:

  • значение всегда хранится в оригинальном <select>
  • Slim Select управляет только UI-слоем
  • браузерная валидация работает на уровне DOM
<form id="user-form">
  <select id="country" name="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>
import SlimSelect fr om 'slim-select'

const countrySelect = new SlimSelect({
  select: '#country'
})

При пустом значении ("") браузерная валидация автоматически фиксирует ошибку valueMissing.


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

Constraint Validation API продолжает работать без дополнительных адаптаций. Используются стандартные свойства:

  • required
  • valueMissing
  • validity
  • validationMessage
  • checkValidity()
  • reportValidity()
const form = document.getElementById('user-form')
const sel ect = document.getElementById('country')

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

    console.log(select.validationMessage)
  }
})

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


Визуализация ошибок и синхронизация состояния

Так как Slim Select создаёт собственную разметку поверх <select>, классические браузерные подсветки не отображаются. Для этого применяется синхронизация состояния валидности с контейнером компонента.

const wrapper = document.querySelector('.ss-main')

function updateValidationState() {
  if (!select.checkValidity()) {
    wrapper.classList.add('is-invalid')
  } else {
    wrapper.classList.remove('is-invalid')
  }
}
.is-invalid {
  border: 1px solid #e74c3c;
}

Обновление состояния обычно привязывается к событию изменения значения.


Обработка события изменения значения

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

const slim = new SlimSelect({
  select: '#country',
  events: {
    afterChange: () => {
      updateValidationState()
    }
  }
})

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


Обязательные поля и пустые значения

При использовании required важно учитывать, что Slim Select может интерпретировать пустое состояние как:

  • '' (пустая строка)
  • null (в случае множественного выбора)
  • [] (multiple select)

Корректная конфигурация options должна обеспечивать явное пустое значение:

<option value="" selected disabled hidden></option>

Для множественного выбора:

<select id="tags" name="tags" multiple required>
  <option value="js">JavaScript</option>
  <option value="ts">TypeScript</option>
</select>

В этом случае валидность определяется длиной массива значений.


Множественный выбор и проверка массива значений

Slim Select в режиме multiple возвращает массив значений, который можно использовать для кастомной логики валидации.

const tags = document.getElementById('tags')

function validateTags() {
  const value = Array.fr om(tags.selectedOptions).map(o => o.value)

  if (value.length < 2) {
    tags.setCustomValidity('Минимум 2 значения')
  } else {
    tags.setCustomValidity('')
  }
}

Метод setCustomValidity интегрируется с HTML5-валидацией и влияет на checkValidity().


Кастомные правила валидации

Constraint Validation API позволяет расширять стандартные проверки без сторонних библиотек.

function validateCountry() {
  const value = select.value

  if (value === 'ru') {
    select.setCustomValidity('Выбор недоступен')
  } else {
    select.setCustomValidity('')
  }
}

Slim Select не конфликтует с этим механизмом, так как он работает поверх DOM-элемента.


Асинхронная проверка данных

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

async function validateServerSide(value) {
  const res = await fetch('/api/validate-country', {
    method: 'POST',
    body: JSON.stringify({ value })
  })

  const data = await res.json()

  if (!data.valid) {
    select.setCustomValidity(data.message)
  } else {
    select.setCustomValidity('')
  }

  updateValidationState()
}

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


Состояния disabled и readonly-аналоги

Slim Select поддерживает синхронизацию с disabled состоянием исходного элемента. При этом:

  • UI блокируется
  • изменение значения становится недоступным
  • валидация пропускается
select.disabled = true

Для имитации readonly обычно используется логическая блокировка через события и отмену изменений.


Работа с aria-атрибутами

Для корректной доступности состояние ошибки синхронизируется с ARIA-атрибутами.

function syncA11yState() {
  const isInvalid = !select.checkValidity()

  select.setAttribute('aria-invalid', isInvalid)
}

Slim Select визуально не управляет ARIA, поэтому синхронизация выполняется вручную через DOM.


Интеграция с общей формовой валидацией

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

function validateForm(form) {
  const fields = form.querySelectorAll('select')

  let isValid = true

  fields.forEach(field => {
    if (!field.checkValidity()) {
      isValid = false
    }
  })

  return isValid
}

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


Поведение при динамическом изменении options

При изменении списка опций требуется синхронизация UI и повторная проверка валидности.

select.innerHTML += `<option value="fr">France</option>`
select.dispatchEvent(new Event('change'))

Slim Select обновляет внутреннее состояние после изменения DOM, но логика валидации остаётся на стороне формы.


Ошибки состояния и консистентность данных

Расхождение между UI и DOM может возникать при:

  • программном изменении значения без события change
  • асинхронном обновлении options
  • ручной модификации DOM вне Slim Select API

В таких случаях валидность проверяется повторно через checkValidity() и повторную синхронизацию состояния компонента.