Стилизация групп

Группы в Tom Select позволяют логически объединять элементы выпадающего списка. Такая структура особенно полезна при работе с большими наборами данных: категориями товаров, странами и городами, языками программирования, тегами, ролями пользователей и другими сущностями.

Tom Select поддерживает группировку через свойство optgroups. Каждая группа получает собственный идентификатор, заголовок и набор связанных элементов.

Пример базовой структуры:

<select id="frameworks" multiple>
    <option value="vue" data-group="frontend">Vue</option>
    <option value="react" data-group="frontend">React</option>
    <option value="laravel" data-group="backend">Laravel</option>
    <option value="django" data-group="backend">Django</option>
</select>
new TomSelect('#frameworks', {
    optgroupField: 'group',
    optgroups: [
        {value: 'frontend', label: 'Frontend'},
        {value: 'backend', label: 'Backend'}
    ]
});

По умолчанию Tom Select отображает заголовки групп стандартным оформлением. Однако библиотека предоставляет широкие возможности для кастомизации внешнего вида.


Структура DOM у групп

Перед стилизацией важно понимать, какие элементы создаёт библиотека.

Tom Select формирует следующую структуру:

<div class="optgroup">
    <div class="optgroup-header">
        Frontend
    </div>

    <div data-value="vue" class="option">
        Vue
    </div>

    <div data-value="react" class="option">
        React
    </div>
</div>

Основные классы:

Класс Назначение
.optgroup Контейнер группы
.optgroup-header Заголовок группы
.option Элемент списка

Эти классы используются как основные точки кастомизации.


Стилизация заголовков групп

Изменение цвета и фона

Наиболее распространённая задача — визуально отделить заголовок группы от элементов списка.

.ts-dropdown .optgroup-header {
    background: #f3f4f6;
    color: #111827;
    padding: 10px 14px;
    font-weight: 600;
    border-bottom: 1px solid #d1d5db;
}

Результат:

  • заголовок получает отдельный фон;
  • текст становится более выразительным;
  • появляется визуальное разделение между секциями.

Использование uppercase

Для административных интерфейсов часто применяются заголовки в верхнем регистре.

.ts-dropdown .optgroup-header {
    text-transform: uppercase;
    letter-spacing: 1px;
    font-size: 12px;
}

Такой стиль делает группы похожими на секции меню.


Добавление отступов

Без дополнительных отступов группы могут выглядеть перегруженно.

.ts-dropdown .optgroup {
    padding-bottom: 12px;
}

.ts-dropdown .optgroup-header {
    margin-bottom: 6px;
}

Это улучшает читаемость длинных списков.


Разделение групп

Добавление границ между группами

Для визуального разделения удобно использовать border.

.ts-dropdown .optgroup {
    border-bottom: 1px solid #e5e7eb;
}

.ts-dropdown .optgroup:last-child {
    border-bottom: none;
}

Такой подход особенно полезен при большом количестве категорий.


Использование внутренних отступов

Иногда достаточно только пространства между блоками.

.ts-dropdown .optgroup {
    margin-bottom: 18px;
}

Минималистичный интерфейс часто выглядит лучше без линий-разделителей.


Стилизация элементов внутри групп

Разные цвета для разных групп

Каждой группе можно назначить собственный класс через кастомный рендеринг.

new TomSelect('#frameworks', {
    optgroupField: 'group',

    render: {
        optgroup_header(data, escape) {
            return `
                <div class="optgroup-header group-${data.value}">
                    ${escape(data.label)}
                </div>
            `;
        }
    }
});

CSS:

.group-frontend {
    background: #dbeafe;
    color: #1e3a8a;
}

.group-backend {
    background: #dcfce7;
    color: #166534;
}

Теперь каждая категория имеет индивидуальное оформление.


Индивидуальные стили option внутри групп

Элементы также можно оформлять по принадлежности к группе.

render: {
    option(data, escape) {
        return `
            <div class="option option-${data.group}">
                ${escape(data.text)}
            </div>
        `;
    }
}
.option-frontend {
    border-left: 3px solid #2563eb;
}

.option-backend {
    border-left: 3px solid #16a34a;
}

Такой подход делает структуру списка более очевидной.


Кастомные шаблоны групп

Полное переопределение заголовка

Tom Select позволяет полностью заменить HTML группы.

new TomSelect('#frameworks', {
    render: {
        optgroup_header(data, escape) {
            return `
                <div class="custom-group-header">
                    <span class="group-icon">?</span>
                    <span class="group-title">
                        ${escape(data.label)}
                    </span>
                </div>
            `;
        }
    }
});

Можно добавлять:

  • иконки;
  • счётчики;
  • бейджи;
  • описания;
  • кнопки;
  • индикаторы состояния.

Добавление количества элементов

Иногда требуется показать число элементов внутри группы.

new TomSelect('#frameworks', {
    render: {
        optgroup_header(data, escape) {

            const count = data.$options.length;

            return `
                <div class="group-header">
                    <span>${escape(data.label)}</span>
                    <span class="group-count">${count}</span>
                </div>
            `;
        }
    }
});

CSS:

.group-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.group-count {
    background: #2563eb;
    color: white;
    border-radius: 999px;
    padding: 2px 8px;
    font-size: 12px;
}

Стилизация активных групп

Подсветка группы при наведении

.ts-dropdown .optgroup:hover .optgroup-header {
    background: #e0f2fe;
}

Такой эффект делает интерфейс более интерактивным.


Подсветка активного option

.ts-dropdown .option.active {
    background: #2563eb;
    color: white;
}

При наличии групп важно, чтобы активный элемент визуально выделялся сильнее заголовков.


Компактные группы

Уменьшение высоты элементов

Для плотных интерфейсов применяются компактные стили.

.ts-dropdown .optgroup-header {
    padding: 4px 8px;
    font-size: 11px;
}

.ts-dropdown .option {
    padding: 5px 8px;
}

Такой режим полезен:

  • в таблицах;
  • в боковых панелях;
  • в админках;
  • в интерфейсах с большим количеством элементов.

Минималистичное оформление

Группы без фона

Иногда оформление заголовков должно быть максимально нейтральным.

.ts-dropdown .optgroup-header {
    background: transparent;
    border: none;
    color: #6b7280;
    font-weight: 500;
}

Такой подход хорошо сочетается с современными минималистичными интерфейсами.


Использование CSS-переменных

Гибкая тема оформления

:root {
    --group-bg: #f9fafb;
    --group-color: #111827;
    --group-border: #d1d5db;
}

.ts-dropdown .optgroup-header {
    background: var(--group-bg);
    color: var(--group-color);
    border-bottom: 1px solid var(--group-border);
}

Преимущества:

  • централизованное управление стилями;
  • удобное переключение тем;
  • упрощённая поддержка проекта.

Тёмная тема

Адаптация групп под dark mode

.dark .ts-dropdown {
    background: #111827;
    border-color: #374151;
}

.dark .optgroup-header {
    background: #1f2937;
    color: #f3f4f6;
}

.dark .option {
    color: #e5e7eb;
}

.dark .option.active {
    background: #2563eb;
}

Тёмная тема требует отдельной настройки контраста:

  • заголовки должны быть различимы;
  • активные элементы — хорошо заметны;
  • разделители — не слишком яркие.

Анимация групп

Плавное изменение цвета

.ts-dropdown .optgroup-header {
    transition:
        background 0.2s ease,
        color 0.2s ease;
}

Анимация hover

.ts-dropdown .optgroup:hover .optgroup-header {
    transform: translateX(2px);
}
.ts-dropdown .optgroup-header {
    transition: transform 0.15s ease;
}

Небольшие анимации делают интерфейс более живым без перегрузки.


Иконки групп

Использование псевдоэлементов

.ts-dropdown .optgroup-header::before {
    content: "▸";
    margin-right: 8px;
    color: #6b7280;
}

Использование SVG

render: {
    optgroup_header(data, escape) {
        return `
            <div class="group-header">
                <svg class="group-icon" viewBox="0 0 24 24">
                    <path d="..."></path>
                </svg>

                <span>${escape(data.label)}</span>
            </div>
        `;
    }
}

SVG позволяет:

  • менять размер без потери качества;
  • анимировать иконки;
  • использовать системные цвета;
  • применять hover-эффекты.

Группы с описаниями

Расширенные заголовки

optgroups: [
    {
        value: 'frontend',
        label: 'Frontend',
        description: 'Клиентская часть приложения'
    }
]
render: {
    optgroup_header(data, escape) {
        return `
            <div class="group-header">
                <div class="title">
                    ${escape(data.label)}
                </div>

                <div class="description">
                    ${escape(data.description)}
                </div>
            </div>
        `;
    }
}

CSS:

.group-header .description {
    font-size: 12px;
    color: #6b7280;
    margin-top: 2px;
}

Sticky-заголовки групп

Фиксация заголовка при прокрутке

При длинных списках полезно закреплять активную группу сверху.

.ts-dropdown .optgroup-header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: white;
}

Такой подход улучшает навигацию по большим наборам данных.


Стилизация через data-атрибуты

Использование data-group

.option[data-group="frontend"] {
    background: #eff6ff;
}

.option[data-group="backend"] {
    background: #f0fdf4;
}

Подход удобен, когда структура формируется динамически.


Адаптивная стилизация

Изменение размеров на мобильных устройствах

@media (max-width: 768px) {

    .ts-dropdown .optgroup-header {
        font-size: 13px;
        padding: 8px 10px;
    }

    .ts-dropdown .option {
        padding: 10px;
    }

}

На сенсорных устройствах важно увеличивать область нажатия.


Стилизация disabled-групп

Отключённые категории

optgroups: [
    {
        value: 'legacy',
        label: 'Устаревшие',
        disabled: true
    }
]

CSS:

.ts-dropdown .optgroup.disabled {
    opacity: 0.5;
}

.ts-dropdown .optgroup.disabled .optgroup-header {
    text-decoration: line-through;
}

Это помогает визуально отделять недоступные секции.


Использование Flexbox в группах

Выравнивание элементов

.group-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

Flexbox особенно полезен при наличии:

  • иконок;
  • бейджей;
  • счётчиков;
  • кнопок;
  • дополнительных меток.

Использование Grid Layout

Сложные заголовки

.group-header {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 10px;
}

Grid удобен для многокомпонентных шаблонов.


Визуальная иерархия

Выделение уровней интерфейса

Группы должны визуально отличаться от обычных элементов списка.

Рекомендуется:

  • использовать меньший размер текста у option;
  • делать заголовки жирнее;
  • применять разные фоны;
  • увеличивать межгрупповые отступы;
  • снижать насыщенность второстепенных элементов.

Пример:

.optgroup-header {
    font-size: 13px;
    font-weight: 700;
}

.option {
    font-size: 14px;
    font-weight: 400;
}

Производительность при сложной стилизации

Большое количество сложных эффектов может ухудшать производительность выпадающего списка.

Особенно затратны:

  • box-shadow;
  • blur-эффекты;
  • сложные SVG;
  • тяжёлые анимации;
  • множественные backdrop-filter.

Для крупных списков рекомендуется:

  • минимизировать анимации;
  • избегать сложных теней;
  • использовать простые селекторы;
  • не перегружать DOM внутри render().

Комбинирование тем оформления

Tom Select хорошо сочетается с:

  • Tailwind CSS;
  • Bootstrap;
  • Bulma;
  • Material UI;
  • собственными дизайн-системами.

Пример с Tailwind-подобным стилем:

.optgroup-header {
    background: #f9fafb;
    color: #374151;
    font-weight: 600;
    padding: 8px 12px;
    border-bottom: 1px solid #e5e7eb;
}

.option.active {
    background: #3b82f6;
    color: white;
}

Полностью кастомизированный пример

new TomSelect('#frameworks', {

    optgroupField: 'group',

    optgroups: [
        {
            value: 'frontend',
            label: 'Frontend'
        },
        {
            value: 'backend',
            label: 'Backend'
        }
    ],

    render: {

        optgroup_header(data, escape) {

            return `
                <div class="custom-group-header group-${data.value}">
                    <span class="title">
                        ${escape(data.label)}
                    </span>

                    <span class="badge">
                        ${data.$options.length}
                    </span>
                </div>
            `;
        },

        option(data, escape) {

            return `
                <div class="custom-option option-${data.group}">
                    ${escape(data.text)}
                </div>
            `;
        }

    }

});
.custom-group-header {
    display: flex;
    justify-content: space-between;
    align-items: center;

    padding: 10px 14px;

    font-weight: 700;

    border-radius: 6px;
}

.group-frontend {
    background: #dbeafe;
    color: #1e40af;
}

.group-backend {
    background: #dcfce7;
    color: #166534;
}

.badge {
    background: rgba(255,255,255,0.7);
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 12px;
}

.custom-option {
    padding: 10px 14px;
}

.custom-option:hover {
    background: #f3f4f6;
}