Шаблон группы

Группировка данных и роль optgroup в Slim Select

Slim Select поддерживает отображение иерархических списков через механизм группировки опций. В HTML-основе это соответствует конструкции optgroup, где набор элементов объединяется под общим заголовком.

Группы используются для структурирования больших списков, упрощения навигации и логического разделения данных внутри выпадающего списка.

Базовая HTML-структура выглядит следующим образом:

<select id="example">
  <optgroup label="Фрукты">
    <option value="apple">Яблоко</option>
    <option value="banana">Банан</option>
  </optgroup>

  <optgroup label="Овощи">
    <option value="carrot">Морковь</option>
    <option value="potato">Картофель</option>
  </optgroup>
</select>

Slim Select автоматически интерпретирует optgroup и преобразует их в собственную структуру компонентов, сохраняя вложенность и заголовки групп.


Внутренняя модель групп в Slim Select

При инициализации Slim Select преобразует DOM-структуру или JSON-данные в объектный формат:

[
  {
    label: "Фрукты",
    options: [
      { text: "Яблоко", value: "apple" },
      { text: "Банан", value: "banana" }
    ]
  },
  {
    label: "Овощи",
    options: [
      { text: "Морковь", value: "carrot" },
      { text: "Картофель", value: "potato" }
    ]
  }
]

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


Шаблон группы через render.optionGroup

В Slim Select кастомизация внешнего вида групп выполняется через параметр render.optionGroup.

Он отвечает за генерацию HTML-разметки заголовка группы.

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

new SlimSelect({
  select: '#example',
  render: {
    optionGroup: (data) => {
      return `<div class="ss-optgroup">${data.label}</div>`;
    }
  }
});

В данном контексте data содержит информацию о группе:

  • label — название группы
  • дополнительные метаданные (если передаются через data-структуру)

Расширенная кастомизация шаблона группы

Шаблон группы часто требует более сложной логики, чем просто вывод текста. Например, добавление количества элементов внутри группы:

new SlimSelect({
  select: '#example',
  render: {
    optionGroup: (data) => {
      const count = data.options ? data.options.length : 0;

      return `
        <div class="ss-optgroup">
          <span class="ss-optgroup-label">${data.label}</span>
          <span class="ss-optgroup-count">${count}</span>
        </div>
      `;
    }
  }
});

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


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

Slim Select не накладывает строгих ограничений на внешний вид групп, что позволяет полностью управлять стилями через CSS.

Пример базовой стилизации:

.ss-optgroup {
  padding: 8px 12px;
  font-weight: 600;
  background: #f5f5f5;
  border-bottom: 1px solid #e0e0e0;
}

.ss-optgroup-label {
  font-size: 13px;
  color: #333;
}

.ss-optgroup-count {
  float: right;
  font-size: 12px;
  color: #888;
}

При необходимости можно реализовать:

  • фиксированные заголовки групп
  • разделители
  • визуальные иконки категорий
  • цветовую дифференциацию групп

Группы при использовании JSON-данных

Slim Select поддерживает инициализацию через массив объектов, где группы задаются явно:

new SlimSelect({
  select: '#example',
  data: [
    {
      label: 'Фрукты',
      options: [
        { text: 'Яблоко', value: 'apple' },
        { text: 'Банан', value: 'banana' }
      ]
    },
    {
      label: 'Овощи',
      options: [
        { text: 'Морковь', value: 'carrot' },
        { text: 'Картофель', value: 'potato' }
      ]
    }
  ]
});

В этом случае структура групп полностью контролируется JavaScript-слоем без необходимости использовать optgroup в HTML.


Динамическое формирование групп

Группы могут формироваться динамически на основе бизнес-логики, например классификации данных:

const items = [
  { text: 'iPhone', value: 'iphone', type: 'phones' },
  { text: 'Samsung', value: 'samsung', type: 'phones' },
  { text: 'MacBook', value: 'macbook', type: 'laptops' }
];

const grouped = items.reduce((acc, item) => {
  const group = item.type;

  if (!acc[group]) {
    acc[group] = {
      label: group,
      options: []
    };
  }

  acc[group].options.push({
    text: item.text,
    value: item.value
  });

  return acc;
}, {});

new SlimSelect({
  select: '#example',
  data: Object.values(grouped)
});

Такой подход позволяет строить группы на основе API-ответов или пользовательских фильтров.


Поведение групп при выборе элементов

Slim Select сохраняет стандартную семантику группировки:

  • группа не является выбираемым элементом (если не изменена логика)
  • выбор осуществляется только на уровне option
  • состояние группы зависит от вложенных элементов

При кастомизации важно учитывать, что изменение шаблона optionGroup не влияет на логику выбора, только на отображение.


Интерактивные группы

Хотя Slim Select не предоставляет встроенного API для раскрытия/сворачивания групп, такая функциональность может быть реализована через кастомный шаблон и обработчики событий.

Пример имитации сворачивания:

new SlimSelect({
  select: '#example',
  render: {
    optionGroup: (data) => {
      return `
        <div class="ss-optgroup" data-group="${data.label}">
          ${data.label}
        </div>
      `;
    }
  }
});

document.addEventListener('click', (e) => {
  const group = e.target.closest('.ss-optgroup');
  if (!group) return;

  const label = group.dataset.group;
  const options = document.querySelectorAll(`[data-group="${label}"] + .ss-option`);

  options.forEach(opt => {
    opt.classList.toggle('hidden');
  });
});

Смешанные сценарии группировки

В сложных интерфейсах группы могут комбинироваться с другими возможностями Slim Select:

  • поиск внутри групп
  • асинхронная подгрузка данных
  • мультивыбор внутри групп
  • фильтрация групп по введённому запросу

Особенно важно учитывать производительность при больших наборах данных, так как каждая группа увеличивает DOM-сложность выпадающего списка.


Особенности рендеринга групп

При использовании кастомного optionGroup шаблона важно учитывать:

  • рендер вызывается при каждом обновлении списка
  • чрезмерно сложная разметка может снижать производительность
  • лучше избегать тяжёлых вычислений внутри шаблона
  • предпочтительно заранее подготавливать данные

Оптимизированный подход — отделение логики подготовки данных от функции рендера:

const renderGroup = (data) => groupTemplates[data.label] || data.label;

Использование групп в сложных UI-компонентах

Группы часто становятся основой для построения интерфейсов фильтрации:

  • каталоги товаров
  • справочники с категориями
  • списки регионов и городов
  • настройки с тематическими разделами

Slim Select в таких сценариях выступает как слой визуализации над структурированными данными, где шаблон группы определяет читаемость и удобство навигации.