В Tom Select визуальная часть полностью отделена от логики, что
позволяет гибко управлять тем, как отображаются элементы интерфейса:
выбранные значения, пункты списка, подсказки, индикаторы состояния.
Основной механизм кастомизации — переопределение шаблонов
(render), через которые формируются DOM-элементы.
Каждый ключевой элемент интерфейса формируется отдельной функцией:
option — элемент выпадающего спискаitem — выбранный элементoption_create — создание нового значенияno_results — отображение пустого результатаoptgroup_header — заголовки группИменно через эти шаблоны внедряются иконки, SVG-графика и любые визуальные компоненты.
new TomSelect("#select", {
render: {
option: function(data, escape) {
return `
<div class="option">
<span class="icon icon-user"></span>
<span class="label">${escape(data.text)}</span>
</div>
`;
}
}
});
В этом механизме отсутствуют ограничения на HTML-структуру, что делает возможным интеграцию как шрифтовых иконок, так и inline-SVG.
Добавление иконок в элементы списка чаще всего реализуется через
данные, передаваемые в объекте опции. Каждая опция может содержать
дополнительные поля: icon, image,
type, color.
{
value: "user_1",
text: "Алексей",
icon: "fa fa-user"
}
Далее эти данные используются в render.option:
render: {
option: function(data, escape) {
return `
<div class="option-item">
<i class="${data.icon}"></i>
<span>${escape(data.text)}</span>
</div>
`;
}
}
Такой подход позволяет отделять данные от представления, сохраняя единый формат источника информации.
Часто для визуализации используются шрифтовые библиотеки, такие как Font Awesome. Tom Select не ограничивает выбор системы иконок, так как работает на уровне DOM.
Пример интеграции:
<link rel="stylesheet" href="fontawesome.css">
render: {
item: function(data, escape) {
return `
<div class="item">
<i class="${data.icon}"></i>
<span>${escape(data.text)}</span>
</div>
`;
}
}
Основной принцип — передача класса иконки через данные, без жесткой привязки к UI-слою.
SVG обеспечивает более гибкий контроль над цветом, размером и анимацией. В отличие от шрифтовых иконок, SVG может быть инлайновым и динамически изменяемым.
render: {
option: function(data, escape) {
return `
<div class="option">
<svg class="icon" width="16" height="16" viewBox="0 0 24 24">
<path d="${data.svgPath}"></path>
</svg>
<span>${escape(data.text)}</span>
</div>
`;
}
}
SVG особенно полезен при необходимости состояния (active, selected, disabled), где цвет иконки меняется через CSS:
.option .icon {
fill: currentColor;
}
Выбранные элементы отображаются отдельно от списка опций и
формируются через render.item. Это позволяет создавать
компактные визуальные компоненты, включающие иконку, текст и
дополнительные индикаторы.
render: {
item: function(data, escape) {
return `
<div class="selected-item">
<span class="avatar"></span>
<span class="text">${escape(data.text)}</span>
</div>
`;
}
}
При необходимости можно добавить статусные индикаторы:
<span class="status status-online"></span>
или комбинировать несколько графических элементов внутри одного элемента.
В интерфейсе Tom Select присутствуют управляющие элементы: стрелка раскрытия списка (caret), кнопка очистки, индикатор загрузки. Они также могут быть изменены через CSS и частично через настройки.
Caret-иконка часто заменяется через CSS:
.ts-control::after {
content: "";
background-image: url("data:image/svg+xml,...");
}
Либо полностью переопределяется через шаблон control:
render: {
dropdown: function() {
return `<div class="dropdown-custom"></div>`;
}
}
Кнопка очистки может быть стилизована как иконка SVG или font-icon. В
стандартной реализации она добавляется через CSS-класс
clear-button.
.clear-button {
background: url("close.svg") no-repeat center;
}
При использовании кастомного рендера возможно полное управление этим элементом:
render: {
item: function(data) {
return `
<div class="item">
<span>${data.text}</span>
<span class="remove-icon">×</span>
</div>
`;
}
}
Семантически кнопка удаления остается частью item, но визуально полностью контролируется разработчиком.
При работе с удаленными источниками данных Tom Select отображает
состояние загрузки. Этот элемент также может быть кастомизирован через
render.loading.
render: {
loading: function() {
return `
<div class="loading-state">
<svg class="spinner" viewBox="0 0 50 50">
<circle cx="25" cy="25" r="20"></circle>
</svg>
</div>
`;
}
}
CSS-анимация позволяет создать плавное вращение:
.spinner {
animation: rotate 1s linear infinite;
}
Группы опций (optgroup) позволяют структурировать список
и добавлять визуальные маркеры для категорий.
render: {
optgroup_header: function(data) {
return `
<div class="group-header">
<span class="group-icon"></span>
<span>${data.label}</span>
</div>
`;
}
}
Это полезно при построении сложных селектов, где категории должны быть визуально различимы.
Графические элементы часто зависят от состояния данных. Например, статус пользователя, тип объекта или уровень приоритета.
{
value: 1,
text: "Сервер 1",
status: "online"
}
render: {
option: function(data) {
return `
<div class="option">
<span class="status ${data.status}"></span>
<span>${data.text}</span>
</div>
`;
}
}
Такой подход делает интерфейс реактивным к данным без изменения логики компонента.
Помимо иконок, могут использоваться аватары и миниатюры изображений.
Tom Select одинаково корректно работает с <img>, SVG
и CSS background.
render: {
item: function(data) {
return `
<div class="item">
<img src="${data.avatar}" class="avatar">
<span>${data.text}</span>
</div>
`;
}
}
Для оптимизации загрузки часто применяются fallback-изображения и lazy-loading через сторонние механизмы.
Графические элементы удобно контролировать через CSS variables, особенно при смене тем оформления.
:root {
--icon-color: #444;
}
.option .icon {
color: var(--icon-color);
}
Состояния hover и selected позволяют дополнительно изменять внешний вид:
.option.selected .icon {
color: #2196f3;
}
Tom Select допускает создание сложных визуальных блоков внутри одного элемента: текст, иконка, бейдж, статус, прогресс-индикатор.
render: {
item: function(data) {
return `
<div class="complex-item">
<span class="icon"></span>
<span class="label">${data.text}</span>
<span class="badge">${data.count}</span>
</div>
`;
}
}
Такая композиция позволяет строить интерфейсы, приближенные к полноценным UI-компонентам, а не просто селекту.