Обязательное поле — это элемент формы, который должен содержать
выбранное значение перед отправкой данных. В стандартном HTML такая
проверка реализуется атрибутом required, однако при
использовании Tom Select появляется дополнительный уровень абстракции:
исходный <select> скрывается, а управление переходит
к JavaScript-компоненту.
Tom Select сохраняет совместимость с HTML-валидацией, но требует понимания особенностей работы с DOM, скрытыми элементами и пользовательским интерфейсом.
Базовый пример обязательного поля:
<form id="user-form">
<select id="country" required>
<option value="">Выберите страну</option>
<option value="kz">Казахстан</option>
<option value="ru">Россия</option>
<option value="uz">Узбекистан</option>
</select>
<button type="submit">Отправить</button>
</form>
new TomSelect('#country');
В этом случае браузер не позволит отправить форму, пока значение не будет выбрано.
requiredПосле инициализации библиотека:
<select>Атрибут required продолжает находиться на оригинальном
элементе, поэтому браузерная валидация остаётся рабочей.
Пример структуры DOM после инициализации:
<select id="country" required hidden tabindex="-1">
Tom Select создаёт визуальный контейнер:
<div class="ts-wrapper">
<div class="ts-control">
<input type="text">
</div>
</div>
При этом именно скрытый <select> участвует в
отправке формы.
Наиболее распространённый сценарий — обязательный выбор одного значения.
<select id="city" required>
<option value="">Выберите город</option>
<option value="astana">Астана</option>
<option value="almaty">Алматы</option>
<option value="karaganda">Караганда</option>
</select>
new TomSelect('#city', {
allowEmptyOption: true
});
Ключевой момент — наличие пустого
<option value="">.
Без него:
required станет бесполезной.Неправильный вариант:
<select required>
<option value="kz">Казахстан</option>
<option value="ru">Россия</option>
</select>
Правильный вариант:
<select required>
<option value="">Выберите страну</option>
<option value="kz">Казахстан</option>
<option value="ru">Россия</option>
</select>
Placeholder помогает визуально обозначить, что значение ещё не выбрано.
new TomSelect('#country', {
placeholder: 'Выберите страну'
});
Однако placeholder не заменяет пустой
<option>.
Ошибочный подход:
<select required>
<option value="kz">Казахстан</option>
</select>
new TomSelect('#country', {
placeholder: 'Выберите страну'
});
В этом случае поле уже содержит значение kz.
Для множественного выбора required работает иначе.
<select id="skills" multiple required>
<option value="js">JavaScript</option>
<option value="ts">TypeScript</option>
<option value="react">React</option>
</select>
new TomSelect('#skills', {
plugins: ['remove_button']
});
Для multiple браузер считает поле валидным, если выбран
хотя бы один элемент.
Проверка работает автоматически:
form.checkValidity();
Если пользователь удалит все элементы:
select.tomselect.clear();
форма снова станет невалидной.
Tom Select предоставляет API для получения текущих значений.
const control = document.querySelector('#country').tomselect;
if (!control.getValue()) {
console.log('Поле обязательно');
}
const skills = document.querySelector('#skills').tomselect;
if (skills.getValue().length === 0) {
console.log('Нужно выбрать хотя бы один навык');
}
checkValidityСтандартная HTML-валидация совместима с Tom Select.
const form = document.querySelector('#form');
form.addEventListener('submit', (e) => {
if (!form.checkValidity()) {
e.preventDefault();
}
});
Более современный вариант:
form.addEventListener('submit', (e) => {
if (!form.reportValidity()) {
e.preventDefault();
}
});
Метод reportValidity():
Для обязательных полей часто требуется собственный текст ошибки.
setCustomValidityconst select = document.querySelector('#country');
select.addEventListener('invalid', () => {
select.setCustomValidity('Необходимо выбрать страну');
});
select.addEventListener('change', () => {
select.setCustomValidity('');
});
Tom Select поддерживает собственные события.
const control = new TomSelect('#country');
control.on('change', (value) => {
if (!value) {
console.log('Поле пустое');
}
});
control.on('change', () => {
const values = control.getValue();
if (values.length === 0) {
console.log('Выберите минимум один элемент');
}
});
Часто требуется визуально показать ошибку.
const select = document.querySelector('#country');
const wrapper = select.tomselect.wrapper;
function validate() {
if (!select.value) {
wrapper.classList.add('invalid');
} else {
wrapper.classList.remove('invalid');
}
}
select.addEventListener('change', validate);
.invalid .ts-control {
border-color: red;
}
Наиболее распространённый сценарий — проверка перед submit.
const form = document.querySelector('#form');
form.addEventListener('submit', (e) => {
const select = document.querySelector('#country');
const tom = select.tomselect;
if (!tom.getValue()) {
e.preventDefault();
tom.wrapper.classList.add('invalid');
}
});
Tom Select поддерживает пустые значения через
allowEmptyOption.
new TomSelect('#country', {
allowEmptyOption: true
});
Без этого параметра пустой <option> может
игнорироваться.
После выбора значения ошибка обычно убирается автоматически.
const control = new TomSelect('#country');
control.on('change', (value) => {
if (value) {
control.wrapper.classList.remove('invalid');
}
});
При динамической загрузке данных обязательность поля сохраняется.
new TomSelect('#users', {
valueField: 'id',
labelField: 'name',
searchField: 'name',
load(query, callback) {
fetch('/api/users?q=' + query)
.then(response => response.json())
.then(data => callback(data));
}
});
Даже если список ещё не загружен:
Иногда требуется запретить отправку формы, пока данные не загружены.
const control = new TomSelect('#users', {
preload: true,
load(query, callback) {
fetch('/api/users')
.then(r => r.json())
.then(data => callback(data));
}
});
form.addEventListener('submit', (e) => {
if (control.loading > 0) {
e.preventDefault();
}
});
HTML required проверяет только наличие хотя бы одного
значения. Для более сложной логики нужна ручная проверка.
const control = new TomSelect('#skills');
form.addEventListener('submit', (e) => {
const values = control.getValue();
if (values.length < 2) {
e.preventDefault();
alert('Выберите минимум 2 навыка');
}
});
Tom Select позволяет комбинировать обязательность и ограничения.
new TomSelect('#skills', {
maxItems: 3
});
Логика:
Удобный подход для больших форм.
<select id="country" data-required="true">
document.querySelectorAll('[data-required]')
.forEach((element) => {
const control = element.tomselect;
if (!control.getValue()) {
control.wrapper.classList.add('invalid');
}
});
Tom Select можно интегрировать со стандартной системой валидации Bootstrap.
if (!control.getValue()) {
control.wrapper.classList.add('is-invalid');
}
.ts-wrapper.is-invalid .ts-control {
border-color: #dc3545;
}
Пример ручной интеграции:
const control = new TomSelect('#country');
control.on('change', () => {
validator.revalidateField('country');
});
После очистки значение снова становится невалидным.
control.clear();
При использовании формы:
form.reset();
Tom Select необходимо синхронизировать:
control.clear();
control.sync();
Атрибут required можно изменять программно.
select.required = true;
select.required = false;
Частый сценарий — поле обязательно только при определённых условиях.
checkbox.addEventListener('change', () => {
if (checkbox.checked) {
select.required = true;
} else {
select.required = false;
}
});
Валидацию можно запускать после blur.
control.on('blur', () => {
if (!control.getValue()) {
control.wrapper.classList.add('invalid');
}
});
При разрешении пользовательских значений обязательность сохраняется.
new TomSelect('#tags', {
create: true,
persist: false
});
Поле считается заполненным:
Если поле отключено:
<select required disabled>
валидация не выполняется.
При динамическом включении:
select.disabled = false;
необходимо обновить состояние:
select.tomselect.enable();
<select required>
<option value="1">One</option>
</select>
Поле уже валидно.
Неправильно:
document.querySelector('.ts-control input').value
Правильно:
select.tomselect.getValue()
Некоторые разработчики ошибочно удаляют атрибут:
select.removeAttribute('required');
Это отключает встроенную HTML-валидацию.
Неправильно:
if (wrapper.classList.contains('has-items'))
Правильно:
if (control.getValue())
<form id="form">
<select id="country" required>
<option value="">Выберите страну</option>
<option value="kz">Казахстан</option>
<option value="ru">Россия</option>
<option value="uz">Узбекистан</option>
</select>
<button type="submit">
Отправить
</button>
</form>
const selectElement = document.querySelector('#country');
const control = new TomSelect('#country', {
allowEmptyOption: true,
placeholder: 'Выберите страну'
});
const form = document.querySelector('#form');
form.addEventListener('submit', (e) => {
if (!control.getValue()) {
e.preventDefault();
selectElement.setCustomValidity(
'Необходимо выбрать страну'
);
control.wrapper.classList.add('invalid');
selectElement.reportValidity();
} else {
selectElement.setCustomValidity('');
control.wrapper.classList.remove('invalid');
}
});
control.on('change', () => {
if (control.getValue()) {
selectElement.setCustomValidity('');
control.wrapper.classList.remove('invalid');
}
});
.invalid .ts-control {
border: 1px solid red;
}