Работа с Choices.js начинается с определения DOM-элементов, к которым будет привязана функциональность библиотеки. В основе лежит принцип: любой поддерживаемый элемент формы может быть преобразован в управляемый компонент через инициализацию экземпляра Choices. Ключевым этапом становится корректный выбор целевых узлов и организация доступа к ним в пределах документа или отдельного компонента интерфейса.
Choices.js поддерживает два основных типа HTML-элементов:
<select> — классический выпадающий список,
включая множественный выбор<input> — поле ввода с режимом автодополнения и
тегированияКаждый из этих элементов может быть преобразован в управляемый компонент, однако поведение и набор возможностей зависят от исходного типа.
Для <select> библиотека расширяет стандартную
семантику выбора, добавляя поиск, кастомные шаблоны и управление списком
опций.
Для <input> формируется динамический список
значений, часто используемый для тегов, автокомплита или
пользовательских значений.
Наиболее распространённый способ получения целевых узлов — использование стандартных DOM-селекторов.
Одиночный элемент выбирается через
document.querySelector, что подходит для простых
сценариев:
const element = document.querySelector('#country-select');
const choices = new Choices(element, {
searchEnabled: true
});
В этом случае инициализация выполняется строго для одного узла,
идентифицируемого по id, классу или атрибуту.
При работе с множественными элементами используется
document.querySelectorAll, возвращающий коллекцию
узлов:
const elements = document.querySelectorAll('.js-choices');
elements.forEach(el => {
new Choices(el, {
removeItemButton: true
});
});
Такой подход применяется при массовой инициализации одинаковых компонентов на странице.
Для структурированного управления целевыми элементами часто
применяется разметка через data-* атрибуты. Это позволяет
отделить поведение от визуальных классов и упрощает масштабирование
интерфейса.
<sel ect data-choice="true"></select>
<select data-choice="true"></select>
Инициализация:
const elements = document.querySelectorAll('[data-choice="true"]');
elements.forEach(el => {
new Choices(el, {
shouldSort: false
});
});
Подобная стратегия особенно полезна в крупных приложениях, где классы используются для стилизации, а атрибуты — для логики.
В ситуациях, когда элементы создаются динамически (например, через AJAX или рендеринг шаблонов), прямой выбор при загрузке документа становится недостаточным. Требуется либо повторная инициализация, либо отслеживание появления узлов.
function initChoices(root = document) {
const elements = root.querySelectorAll('.js-choices');
elements.forEach(el => {
if (!el.dataset.choicesInitialized) {
el.dataset.choicesInitialized = 'true';
new Choices(el, {
searchEnabled: true
});
}
});
}
Использование флага dataset предотвращает повторную
инициализацию одного и того же элемента.
Для автоматического отслеживания новых узлов применяется
MutationObserver:
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.matches('.js-choices')) {
new Choices(node);
}
if (node.nodeType === 1) {
const nested = node.querySelectorAll('.js-choices');
nested.forEach(el => new Choices(el));
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
Такой механизм обеспечивает автоматическую привязку к динамически добавляемым элементам интерфейса.
При использовании сложных интерфейсных компонентов важно ограничивать область поиска элементов, чтобы избежать конфликтов между модулями.
const container = document.querySelector('.form-section');
const elements = container.querySelectorAll('.js-choices');
elements.forEach(el => new Choices(el));
Привязка к контейнеру снижает вероятность случайной инициализации сторонних элементов с аналогичными классами.
В рамках SPA или компонентных систем (например, React или Vue без обёрток) выбор целевых элементов часто локализуется внутри жизненного цикла компонента.
class FormModule {
constructor(root) {
this.root = root;
this.init();
}
init() {
this.elements = this.root.querySelectorAll('.js-choices');
this.instances = Array.fr om(this.elements).map(el =>
new Choices(el, {
searchEnabled: true
})
);
}
}
Такой подход позволяет изолировать экземпляры и управлять их жизненным циклом через объектную структуру.
Перед инициализацией выполняется проверка соответствия элемента требованиям библиотеки. Основной критерий — наличие поддерживаемого тега.
function isValidTarget(el) {
return el && (el.tagName === 'SELECT' || el.tagName === 'INPUT');
}
Использование проверки предотвращает ошибки при случайном выборе неподходящих узлов.
Часто требуется исключить уже инициализированные элементы или отключённые поля.
const elements = document.querySelectorAll(
'select.js-choices:not([disabled])'
);
elements.forEach(el => new Choices(el));
Комбинирование CSS-селекторов позволяет гибко управлять выборкой без дополнительной логики в JavaScript.
В сложных формах разные группы элементов могут требовать разных настроек. В таких случаях выбор осуществляется по отдельным селекторам.
const simple = document.querySelectorAll('.js-choices-simple');
const advanced = document.querySelectorAll('.js-choices-advanced');
simple.forEach(el => {
new Choices(el, {
searchEnabled: false
});
});
advanced.forEach(el => {
new Choices(el, {
searchEnabled: true,
removeItemButton: true
});
});
Разделение выборки по классам обеспечивает предсказуемое поведение конфигураций.
При повторном рендеринге интерфейса требуется контролировать удаление предыдущих экземпляров. Для этого хранится ссылка на объект Choices:
const element = document.querySelector('#tags');
const instance = new Choices(element);
// последующая очистка
instance.destroy();
После вызова destroy элемент возвращается в исходное
состояние, что позволяет безопасно повторно выполнить выбор и
инициализацию.
Механизм работы с DOM в Choices.js строится вокруг трёх ключевых принципов:
Такая модель обеспечивает гибкость интеграции библиотеки в различные архитектуры фронтенда и позволяет масштабировать поведение без усложнения логики инициализации.