Шаблон для сообщений

В Choices.js текстовые сообщения интерфейса и шаблоны отображения элементов формируются через набор конфигурационных параметров и callback-функций, позволяющих полностью контролировать HTML-разметку списка, выбранных значений и системных сообщений компонента.

Формирование визуального представления в Choices.js строится вокруг функций, возвращающих строки HTML. Основные точки расширения:

  • itemTemplate — шаблон выбранного элемента
  • choiceTemplate — шаблон элемента списка
  • groupTemplate — шаблон группы опций
  • системные сообщения (noResultsText, loadingText и др.)

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


Шаблон выбранного элемента (itemTemplate)

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

const example = new Choices('#select', {
  itemTemplate: (classNames, data) => {
    return `
      <div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : ''}"
           data-item
           data-id="${data.id}"
           data-value="${data.value}">
        <span class="custom-label">${data.label}</span>
        <button type="button" class="${classNames.button}" data-button>
          ×
        </button>
      </div>
    `;
  }
});

Ключевые элементы объекта data:

  • value — значение опции
  • label — отображаемый текст
  • id — внутренний идентификатор
  • disabled — флаг недоступности
  • highlighted — состояние наведения/фокуса

Особенности реализации:

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

Шаблон элементов списка (choiceTemplate)

choiceTemplate управляет отображением элементов выпадающего списка. Это наиболее часто переопределяемая часть UI.

const example = new Choices('#select', {
  choiceTemplate: (classNames, data) => {
    return `
      <div class="${classNames.item} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}"
           data-choice
           data-id="${data.id}"
           data-value="${data.value}"
           data-select-text="Выбрать">
        <span class="option-title">${data.label}</span>
        ${data.customProperties?.description
          ? `<small class="option-desc">${data.customProperties.description}</small>`
          : ''}
      </div>
    `;
  }
});

Поведение шаблона:

  • используется при рендеринге списка опций
  • поддерживает условное отображение дополнительных данных
  • позволяет внедрять сложную структуру (иконки, описания, бейджи)

Расширенные данные часто передаются через customProperties:

{
  value: 'us',
  label: 'United States',
  customProperties: {
    description: 'North America',
    code: 'US'
  }
}

Шаблоны групп (groupTemplate)

При использовании группировки опций (optgroup) применяется groupTemplate.

groupTemplate: (classNames, data) => {
  return `
    <div class="${classNames.group}">
      <div class="${classNames.groupHeading}">
        ${data.label}
      </div>
    </div>
  `;
}

Свойства data:

  • label — название группы
  • disabled — состояние блокировки
  • id — идентификатор группы

Группы часто используются для:

  • иерархических списков стран/городов
  • категорий товаров
  • фильтров с логической структурой

Системные сообщения интерфейса

Choices.js содержит набор текстовых сообщений, которые отображаются в разных состояниях компонента.

Сообщение при отсутствии результатов

noResultsText: 'Ничего не найдено'

Используется при фильтрации, если совпадений нет.


Сообщение при пустом списке

noChoicesText: 'Нет доступных вариантов'

Активируется, когда список опций пуст или отключён.


Текст загрузки

loadingText: 'Загрузка...'

Отображается при асинхронной подгрузке данных.


Текст добавления нового элемента

addItemText: (value) => {
  return `Добавить "${value}"`;
}

Позволяет динамически формировать сообщение на основе ввода пользователя.


Ограничение количества выбранных элементов

maxItemText: (maxItemCount) => {
  return `Можно выбрать не более ${maxItemCount} элементов`;
}

Используется при включённом ограничении maxItemCount.


Предотвращение дубликатов

uniqueItemText: 'Этот элемент уже выбран'

Выводится при попытке добавить уже выбранное значение.


Полная кастомизация через callbackOnCreateTemplates

Наиболее гибкий механизм переопределения шаблонов реализуется через callbackOnCreateTemplates.

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

      choice: (classNames, data) => {
        return template(`
          <div class="${classNames.item} ${classNames.itemChoice}">
            ${data.label}
          </div>
        `);
      }
    };
  }
});

Особенность данного подхода:

  • доступ к внутреннему механизму генерации DOM
  • возможность централизованного контроля всех шаблонов
  • поддержка оптимизаций библиотеки через template()

Безопасность HTML в шаблонах

Choices.js не экранирует HTML автоматически в пользовательских шаблонах. Это создаёт важные требования:

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

Пример небезопасного подхода:

label: "<img src=x oner ror=alert(1)>"

Без обработки это приведёт к XSS.

Корректный подход:

function escapeHtml(str) {
  return str
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#039;');
}

Динамическое поведение шаблонов

Шаблоны могут зависеть от состояния данных:

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

Пример:

choiceTemplate: (classNames, data) => {
  const status = data.selected ? 'selected' : 'available';

  return `
    <div class="${classNames.item} ${status}">
      ${data.label}
    </div>
  `;
}

Интеграция иконок и сложных UI-элементов

Choices.js позволяет внедрять произвольный HTML, включая иконки:

choiceTemplate: (classNames, data) => {
  return `
    <div class="${classNames.item}">
      <span class="icon">${data.customProperties.icon}</span>
      <span class="text">${data.label}</span>
    </div>
  `;
}

Применение:

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

Производительность шаблонов

Переопределённые шаблоны влияют на производительность при большом количестве элементов.

Рекомендации:

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

Общая структура сообщений и шаблонов

Компонентные шаблоны Choices.js образуют единую систему:

  • choiceTemplate — входной список
  • itemTemplate — выбранные элементы
  • group-шаблоны — логическая структура
  • текстовые сообщения — состояние UI

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