Группировка опций в 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 работает глобально, включая все группы. Однако результат отображения сохраняет иерархию:
Ключевой момент заключается в том, что фильтрация применяется к опциям, а не к группам как сущностям.
Сортировка в группированных списках зависит от нескольких факторов:
shouldSortsorter (кастомная функция)choicesПример отключения автоматической сортировки:
new Choices('#select', {
shouldSort: false
});
При включённой сортировке элементы внутри групп могут перемещаться, но структура групп сохраняется.
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
для отображения дополнительных элементов интерфейса.
Группировка особенно важна при больших списках, где без структуры интерфейс становится перегруженным.
Рекомендации по использованию:
При активном поиске:
При необходимости можно реализовать поведение «сворачивания пустых
групп» через кастомные шаблоны или фильтрацию данных перед передачей в
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 группировка
помогает:
Группы при этом не влияют на отображение выбранных тегов, но помогают при поиске и выборе новых значений.
Несмотря на гибкость, существуют системные ограничения:
Эти ограничения компенсируются кастомизацией шаблонов и динамическим
обновлением данных через setChoices.