Группировка опций

Группировка опций в Choices.js реализуется через механизм, который концептуально соответствует HTML-элементу <optgroup>, но в библиотеке дополнительно расширяется возможностями динамической загрузки, кастомного рендера и управления состоянием групп. Основная цель группировки — структурировать длинные списки значений, повысить читаемость интерфейса и ускорить поиск нужного элемента в больших наборах данных.


Базовая структура группированных данных

Choices.js поддерживает передачу данных в виде массива объектов, где каждый объект может представлять как одиночную опцию, так и группу.

Формат группы

Группа описывается объектом со следующими ключевыми свойствами:

  • label — заголовок группы
  • id (опционально) — уникальный идентификатор группы
  • disabled (опционально) — отключение всей группы
  • choices — массив опций внутри группы

Формат опции внутри группы

Каждая опция содержит:

  • value — значение
  • label — отображаемый текст
  • selected — начальное состояние выбора
  • disabled — блокировка конкретного элемента

Пример статической группировки

const element = document.querySelector('#select');

const choices = new Choices(element, {
  shouldSort: false,
  searchEnabled: true
});

choices.setChoices([
  {
    label: 'Фронтенд',
    id: 'frontend',
    choices: [
      { value: 'react', label: 'React' },
      { value: 'vue', label: 'Vue' },
      { value: 'angular', label: 'Angular' }
    ]
  },
  {
    label: 'Бэкенд',
    id: 'backend',
    choices: [
      { value: 'node', label: 'Node.js' },
      { value: 'django', label: 'Django' },
      { value: 'laravel', label: 'Laravel' }
    ]
  }
]);

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


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

По умолчанию поиск в Choices.js работает глобально, включая все группы. Однако результат отображения сохраняет иерархию:

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

Ключевой момент заключается в том, что фильтрация применяется к опциям, а не к группам как сущностям.


Управление сортировкой внутри групп

Сортировка в группированных списках зависит от нескольких факторов:

  • shouldSort
  • sorter (кастомная функция)
  • порядок элементов в choices

Пример отключения автоматической сортировки:

new Choices('#select', {
  shouldSort: false
});

При включённой сортировке элементы внутри групп могут перемещаться, но структура групп сохраняется.


Динамическая группировка через setChoices

Choices.js позволяет обновлять структуру в рантайме. Это особенно важно при работе с API.

fetch('/api/options')
  .then(res => res.json())
  .then(data => {
    choices.setChoices(data, 'value', 'label', true);
  });

Для группированных данных API должен возвращать вложенную структуру:

[
  {
    "label": "Языки",
    "choices": [
      { "value": "js", "label": "JavaScript" },
      { "value": "py", "label": "Python" }
    ]
  }
]

Отключение группы целиком

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

{
  label: 'Экспериментальные технологии',
  disabled: true,
  choices: [
    { value: 'webgpu', label: 'WebGPU' },
    { value: 'wasm', label: 'WebAssembly' }
  ]
}

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


Кастомизация отображения групп

Choices.js предоставляет шаблоны рендера, включая групповые заголовки.

Основные шаблоны:

  • group — контейнер группы
  • groupHeading — заголовок группы
  • choice — элемент внутри группы

Пример кастомного заголовка:

new Choices('#select', {
  callbackOnCreateTemplates: function (template) {
    return {
      groupHeading: (classNames, data) => {
        return template(`
          <div class="${classNames.itemGroup}">
            <span>${data.label}</span>
          </div>
        `);
      }
    };
  }
});

Кастомизация позволяет добавлять:

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

Иконографика и расширенная визуализация групп

Группы часто используются совместно с визуальными маркерами. Например:

{
  label: 'Базы данных',
  choices: [
    { value: 'postgres', label: 'PostgreSQL', customProperties: { icon: 'db' } },
    { value: 'mongo', label: 'MongoDB', customProperties: { icon: 'leaf' } }
  ]
}

В шаблоне рендера можно использовать customProperties для отображения дополнительных элементов интерфейса.


Работа с большими наборами данных

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

Рекомендации по использованию:

  • ограничивать количество элементов в группе (20–50 максимум)
  • использовать lazy loading через API
  • избегать глубокой вложенности (Choices.js не поддерживает многоуровневые группы)
  • отключать сортировку при критической важности структуры

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

При активном поиске:

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

При необходимости можно реализовать поведение «сворачивания пустых групп» через кастомные шаблоны или фильтрацию данных перед передачей в setChoices.


Имитация вложенных групп

Choices.js не поддерживает многоуровневые optgroup, однако возможно имитировать структуру через плоскую модель:

[
  {
    label: 'Backend / Node.js',
    value: 'node'
  },
  {
    label: 'Backend / Django',
    value: 'django'
  }
]

Либо использовать разделение через строки заголовков, если требуется более сложная визуальная иерархия.


Группы и состояние выбора

Состояние выбора внутри групп работает независимо:

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

Пример обработки:

const selected = choices.getValue(true);

const backend = selected.filter(v =>
  ['node', 'django', 'laravel'].includes(v)
);

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

В режимах multiple и searchable группировка помогает:

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

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


Ограничения группировки

Несмотря на гибкость, существуют системные ограничения:

  • отсутствует нативная поддержка вложенных групп
  • нет отдельного API для управления группами после рендера (только через пересоздание данных)
  • фильтрация групп ограничена логикой выбора элементов
  • нет встроенного collapse/expand для групп

Эти ограничения компенсируются кастомизацией шаблонов и динамическим обновлением данных через setChoices.