Server-side rendering в контексте использования Tom Select
представляет собой подход, при котором базовая разметка
<select> и его опций формируется на сервере, а
клиентская библиотека выполняет только инициализацию поведения, расширяя
уже готовую DOM-структуру. Такой подход снижает нагрузку на клиент,
улучшает индексируемость и обеспечивает предсказуемое отображение до
выполнения JavaScript.
Tom Select не требует обязательного SSR, но корректно работает в
сценариях, где HTML уже содержит заранее сформированный список
<option> элементов. В этом случае библиотека не
создает данные с нуля, а «подхватывает» существующую структуру.
Ключевая идея: SSR отвечает за данные и разметку, Tom Select — за интерактивность.
На стороне сервера формируется стандартный HTML-элемент:
<select id="countries" multiple>
<option value="kz">Kazakhstan</option>
<option value="ru">Russia</option>
<option value="de">Germany</option>
<option value="jp">Japan</option>
</select>
После гидратации на клиенте Tom Select превращает этот элемент в интерактивный компонент:
new TomSelect("#countries");
В SSR-режиме важно, что:
option уже присутствуют в DOMvalue строго определеныTom Select при инициализации проходит по DOM-структуре
<select> и строит внутренние индексы:
SSR-данные преобразуются в внутренний формат без дополнительных запросов.
Пример:
<select id="tags" multiple>
<option value="js" selected>JavaScript</option>
<option value="ts">TypeScript</option>
<option value="css">CSS</option>
</select>
new TomSelect("#tags");
Результат инициализации:
JavaScript уже выбранОдним из ключевых сценариев SSR является передача предварительно выбранных значений.
Сервер генерирует:
<select id="users" multiple>
<option value="1" selected>Alex</option>
<option value="2">Maria</option>
<option value="3" selected>John</option>
</select>
Tom Select при инициализации:
new TomSelect("#users");
Поведение:
selectedКлючевой принцип: DOM является источником истины при SSR.
SSR часто комбинируется с динамической загрузкой данных. В этом случае сервер предоставляет начальный набор опций, а клиент расширяет их через API.
<select id="products">
<option value="100">Laptop</option>
<option value="101">Phone</option>
</select>
new TomSelect("#products", {
load: function(query, callback) {
fetch(`/api/products?q=${encodeURIComponent(query)}`)
.then(res => res.json())
.then(data => {
callback(data.items);
});
}
});
Особенность SSR-гибрида:
Одной из частых ошибок SSR-интеграции является повторное создание экземпляра Tom Select на уже обработанном элементе.
Проблемный сценарий:
new TomSelect("#countries");
new TomSelect("#countries");
Последствия:
Правильный подход:
if (!document.querySelector("#countries").tomselect) {
new TomSelect("#countries");
}
Tom Select сохраняет ссылку на инстанс в DOM-узле, что позволяет проверять состояние инициализации.
Сервер может передавать состояние недоступности элементов:
<select id="payment">
<option value="card">Card</option>
<option value="crypto" disabled>Crypto</option>
<option value="cash">Cash</option>
</select>
Tom Select сохраняет это поведение:
Tom Select позволяет переопределять отображение опций. При SSR важно, что сервер генерирует только базовую структуру, а клиент отвечает за визуализацию.
new TomSelect("#countries", {
render: {
option: function(data, escape) {
return `<div>
<span class="label">${escape(data.text)}</span>
</div>`;
}
}
});
SSR при этом поставляет:
<option value="kz">Kazakhstan</option>
Render-функции:
Иногда сервер передает дополнительные данные через атрибуты:
<option value="kz" data-region="asia">Kazakhstan</option>
Tom Select считывает эти данные и добавляет их в dataset:
new TomSelect("#countries", {
render: {
option: function(data, escape) {
return `<div>
${escape(data.text)}
<small>${escape(data.region)}</small>
</div>`;
}
}
});
SSR-данные расширяют клиентскую модель без дополнительных запросов.
Tom Select интегрируется с <form> без потери
SSR-состояния.
<form>
<select id="lang" name="lang">
<option value="en" selected>English</option>
<option value="ru">Russian</option>
</select>
</form>
После инициализации:
new TomSelect("#lang");
Отправка формы:
SSR не исключает возможность изменения набора данных после загрузки страницы.
const ts = new TomSelect("#countries");
ts.addOption({ value: "fr", text: "France" });
ts.refreshOptions(false);
Важная особенность:
При удалении компонента важно сбросить состояние, иначе SSR-инициализированные элементы могут оставить «следы» в памяти.
const ts = new TomSelect("#countries");
ts.destroy();
После destroy:
<select>В сложных приложениях возможно несоответствие между серверной разметкой и клиентскими данными.
Пример:
Сервер:
<option value="1" selected>A</option>
Клиент получает обновленные данные API:
ts.clear();
ts.addOption({ value: "2", text: "B" });
ts.addItem("2");
Tom Select не требует пересоздания компонента — SSR используется только как bootstrap-слой.
При использовании частичного SSR (например, обновление фрагментов страницы без перезагрузки) важно переинициализировать Tom Select только на новых узлах.
document.querySelectorAll("select").forEach(el => {
if (!el.tomselect) {
new TomSelect(el);
}
});
Это предотвращает:
Использование SSR с Tom Select влияет на производительность в нескольких аспектах:
Однако при большом количестве <option> необходимо
учитывать:
В таких случаях часто применяется компромисс:
load()Одним из ключевых преимуществ SSR является детерминированность состояния:
Tom Select в этом сценарии выступает как слой поведения поверх уже стабильной модели данных.