Tom Select строит интерфейс вокруг набора заранее определённых CSS-классов, которые присваиваются ключевым DOM-узлам: контейнеру, полю ввода, выпадающему списку, выбранным элементам и состояниям (активный, disabled, выбранный). Архитектура библиотеки предполагает два уровня управления внешним видом: через стандартные классы по умолчанию и через систему переопределения classNames, позволяющую полностью заменить или расширить разметочную семантику.
Базовая структура генерируемой разметки включает элементы:
ts-wrapper — обёртка компонентаts-control — зона ввода и отображения выбранных
значенийts-dropdown — выпадающий списокoption — элементы спискаitem — выбранные значенияactive, selected, disabled —
состояния элементовЭти классы формируют основу стилей, и любые изменения внешнего вида должны учитывать их приоритет и специфичность.
Основной механизм кастомизации в Tom Select реализуется через объект
classNames, который передаётся в конфигурации
экземпляра:
new TomSelect('#select', {
classNames: {
wrapper: 'my-wrapper',
control: 'my-control',
dropdown: 'my-dropdown',
dropdownContent: 'my-dropdown-content',
input: 'my-input',
item: 'my-item',
option: 'my-option',
active: 'is-active',
selected: 'is-selected',
disabled: 'is-disabled',
focus: 'is-focused',
loading: 'is-loading'
}
});
Каждое свойство объекта соответствует определённой части UI. При наличии значения библиотека добавляет указанный класс к соответствующему элементу, не удаляя системные классы, если не предусмотрено обратное поведение через кастомную сборку.
Важно учитывать, что переопределение не заменяет структуру DOM, а лишь расширяет её. Это позволяет сохранять совместимость с внутренней логикой библиотеки.
CSS в контексте Tom Select подчиняется стандартной каскадной модели, где итоговый стиль зависит от:
!importantПоскольку библиотека использует фиксированные классы, переопределение часто требует более специфичных селекторов:
.my-control.ts-control {
border: 2px solid #3b82f6;
border-radius: 8px;
}
Комбинирование пользовательского класса и встроенного класса повышает
приоритет без необходимости использовать !important.
Класс wrapper играет ключевую роль, поскольку
оборачивает весь компонент. Это позволяет задавать глобальную тему для
конкретного экземпляра:
new TomSelect('#select', {
classNames: {
wrapper: 'select-theme-dark'
}
});
Далее стили могут быть полностью изолированы:
.select-theme-dark .ts-control {
background: #111827;
color: #f9fafb;
}
.select-theme-dark .ts-dropdown {
background: #1f2937;
border-color: #374151;
}
Такой подход используется для создания нескольких визуальных тем без вмешательства в глобальные стили библиотеки.
Состояния элементов управляются через отдельные классы, что позволяет точно контролировать поведение интерфейса:
active — элемент под курсоромselected — выбранное значениеdisabled — недоступный элементfocus — фокус вводаloading — состояние загрузкиПример кастомизации состояния:
.is-active {
background-color: rgba(59, 130, 246, 0.15);
}
.is-selected {
background-color: #2563eb;
color: white;
}
.is-disabled {
opacity: 0.4;
pointer-events: none;
}
Использование собственных классов через classNames
позволяет полностью заменить стандартные имена:
new TomSelect('#select', {
classNames: {
active: 'state-active',
selected: 'state-selected'
}
});
При интеграции в крупные проекты ключевой проблемой становится пересечение глобальных CSS-правил. Tom Select не использует Shadow DOM, поэтому изоляция достигается через:
Пример неймспейса:
new TomSelect('#select', {
classNames: {
wrapper: 'app-select app-select--primary'
}
});
.app-select.app-select--primary .ts-control {
border-color: #6366f1;
}
Такой подход снижает риск коллизий с UI-библиотеками и глобальными reset-стилями.
При необходимости создания полностью кастомного UI возможно переопределение всех ключевых классов:
new TomSelect('#select', {
classNames: {
wrapper: 'custom-select',
control: 'custom-control',
dropdown: 'custom-dropdown',
option: 'custom-option',
item: 'custom-item',
input: 'custom-input'
}
});
В этом случае встроенные стили Tom Select становятся вторичными, а визуальная система строится поверх пользовательской архитектуры CSS.
Tom Select активно изменяет классы в runtime в зависимости от пользовательских действий. Это требует учёта динамики при проектировании стилей.
Пример поведения:
dropdown-activeinput-activehas-itemsКастомизация:
.ts-wrapper.has-items .ts-control {
padding-top: 6px;
padding-bottom: 6px;
}
Динамические классы позволяют строить адаптивные интерфейсы без необходимости вмешательства в JavaScript-логику.
При использовании Tailwind, Bootstrap или аналогичных систем часто возникает задача согласования классов.
Подходы:
new TomSelect('#select', {
classNames: {
wrapper: 'tw-relative tw-w-full'
}
});
.ts-control.is-focused {
outline: 2px solid #60a5fa;
}
Некоторые фреймворки обнуляют стили input, что требует явного восстановления:
.ts-control input {
all: unset;
width: 100%;
}
Дополнительный уровень гибкости достигается через введение модификаторов состояния на уровне wrapper:
new TomSelect('#select', {
onInitialize() {
this.wrapper.classList.add('select--initialized');
}
});
.select--initialized .ts-dropdown {
opacity: 1;
transform: translateY(0);
}
Такой подход используется для анимаций появления и сложных переходов состояний.
При масштабировании проекта важно избегать хаотичного наращивания специфичности. Рекомендуется:
!importantПример структурированного CSS:
.select .ts-control { }
.select.is-focused .ts-control { }
.select.is-disabled .ts-control { }
Такая схема обеспечивает предсказуемое поведение при изменении classNames и расширении функциональности компонента.