В основе системы отображения элементов в Tom Select лежит набор
функций render, отвечающих за генерацию HTML-структур
отдельных частей интерфейса. Каждый визуальный компонент — опция,
выбранный элемент, группа, заголовок, сообщение загрузки — формируется
через шаблонную функцию, возвращающую HTML-строку.
Подход не использует полноценные шаблонизаторы или виртуальный DOM. Вместо этого применяется прямое формирование строк HTML с последующей вставкой в DOM через внутренние механизмы библиотеки. Это обеспечивает высокую производительность и предсказуемость рендеринга.
Ключевой принцип: каждый элемент UI является независимой единицей, формируемой отдельным шаблоном.
Внутренняя конфигурация рендеринга задаётся через объект
render, передаваемый при инициализации:
new TomSelect('#select', {
render: {
option: function(data, escape) {
return `<div>${escape(data.text)}</div>`;
}
}
});
Каждая функция получает:
data — объект данных элемента (option, item,
group)escape — функция экранирования HTMLself (в некоторых контекстах) — ссылка на экземпляр
селектаШаблон option определяет внешний вид элементов
выпадающего списка.
render: {
option: (data, escape) => {
return `
<div class="option">
<span class="label">${escape(data.text)}</span>
</div>
`;
}
}
dataПример расширенного шаблона:
option: (data, escape) => `
<div class="option">
<img src="${escape(data.avatar)}" class="avatar">
<div class="content">
<div class="title">${escape(data.text)}</div>
<div class="subtitle">${escape(data.role)}</div>
</div>
</div>
`
item отвечает за отображение выбранных значений внутри
инпута.
render: {
item: (data, escape) => `
<div class="item">
${escape(data.text)}
</div>
`
}
Расширенный пример:
item: (data, escape) => `
<div class="item">
<span class="tag">${escape(data.text)}</span>
<span class="remove">×</span>
</div>
`
Для группированных списков используется
optgroup_header.
render: {
optgroup_header: (data, escape) => `
<div class="optgroup-header">
${escape(data.label)}
</div>
`
}
Группы не являются интерактивными элементами выбора, но могут быть стилизованы как секции.
При асинхронной подгрузке данных используется
loading.
render: {
loading: () => `
<div class="loading">
Загрузка данных...
</div>
`
}
Особенности:
load() или async fetchОтображается при отсутствии совпадений в фильтре.
render: {
no_results: () => `
<div class="no-results">
Ничего не найдено
</div>
`
}
Используется в механизме поиска по списку и может зависеть от
searchField.
Позволяют добавлять статические блоки в верхнюю и нижнюю часть списка.
render: {
dropdown_header: () => `
<div class="dropdown-header">
Выберите значение
</div>
`,
dropdown_footer: () => `
<div class="dropdown-footer">
Всего элементов: 120
</div>
`
}
Применение:
Функция escape критична для безопасности. Она
предотвращает XSS-уязвимости при вставке пользовательских данных в
HTML.
Пример:
render: {
option: (data, escape) => `
<div>${escape(data.text)}</div>
`
}
<>&"'Игнорирование escape допустимо только при полной
уверенности в безопасности источника данных.
Шаблоны напрямую работают с произвольными полями объектов:
{
value: 1,
text: "Разработка",
icon: "/icons/dev.svg",
meta: {
count: 42
}
}
Использование:
option: (data, escape) => `
<div>
<img src="${escape(data.icon)}">
<span>${escape(data.text)}</span>
<small>${escape(data.meta.count)}</small>
</div>
`
| Тип | Контекст | Назначение |
|---|---|---|
| option | dropdown | выбор элемента |
| item | input | отображение выбранного |
Разделение позволяет независимо контролировать визуальные представления одного и того же набора данных.
HTML-шаблоны тесно связаны со стилями. Обычно используются предсказуемые классы:
optionitemoptgroup-headerno-resultsПример:
option: (data, escape) => `
<div class="option option--custom">
${escape(data.text)}
</div>
`
Такой подход позволяет комбинировать стандартные стили Tom Select и пользовательские темы.
Шаблоны могут содержать условные конструкции:
option: (data, escape) => `
<div class="option">
${data.disabled
? `<span class="disabled">${escape(data.text)}</span>`
: `<span>${escape(data.text)}</span>`
}
</div>
`
Применение:
Шаблоны поддерживают inline SVG:
item: (data, escape) => `
<div class="item">
<svg class="icon" viewBox="0 0 24 24">
<path d="..."></path>
</svg>
${escape(data.text)}
</div>
`
SVG предпочтительнее raster-иконок при высокой плотности интерфейсов.
Рендеринг в Tom Select оптимизирован под частые обновления списка. Однако сложные шаблоны могут влиять на производительность.
Факторы влияния:
Рекомендуется:
Для унификации интерфейса шаблоны выносятся в отдельные функции:
const renderOption = (data, escape) => `
<div class="option">${escape(data.text)}</div>
`;
new TomSelect('#select', {
render: {
option: renderOption,
item: renderOption
}
});
Это снижает дублирование и упрощает поддержку UI.
Несмотря на гибкость, система имеет ограничения:
Тем не менее, такая модель обеспечивает высокую скорость работы и предсказуемое поведение интерфейса без дополнительных абстракций.