Dropdown Header

В интерфейсе выпадающего списка Tom Sel ect заголовок dropdown играет роль структурного и функционального элемента, который отделяет служебную область списка от его содержимого и задаёт контекст для отображаемых опций. Он используется для визуального оформления, управления состоянием списка и добавления интерактивных элементов (поиск, фильтры, действия) непосредственно внутри выпадающей панели.

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

Dropdown Header в Tom Select внедряется как отдельный DOM-блок, размещаемый в верхней части контейнера выпадающего списка. Он не является частью набора опций и не участвует в механизме выбора значений. Его основная задача — расширение стандартного UI компонента без модификации внутренней логики выбора элементов.

Структурно выпадающий список Tom Select можно представить следующим образом:

  • контейнер dropdown

    • header (опционально)
    • search input (если включён)
    • список опций
    • сообщения состояния (empty, loading)

Такое разделение позволяет внедрять управляющие элементы без вмешательства в rendering опций.

Подключение функционала dropdown header через plugin

В Tom Select расширение функциональности выполняется через систему плагинов. Dropdown Header реализуется отдельным модулем, подключаемым через параметр plugins.

Базовая активация:

new TomSelect("#select", {
  plugins: ['dropdown_header'],
  dropdownHeader: {
    title: 'Выбор элемента'
  }
});

При инициализации библиотека регистрирует plugin, который модифицирует процесс построения dropdown и добавляет дополнительный контейнер в DOM.

Конфигурационные параметры

Плагин dropdown header поддерживает набор параметров, определяющих поведение и внешний вид заголовка:

  • title — текст заголовка, отображаемый в верхней части dropdown
  • headerClass — дополнительный CSS класс для стилизации контейнера
  • html — возможность передачи HTML-разметки вместо текстовой строки
  • closeButton — флаг отображения кнопки закрытия dropdown
  • onClose — callback, вызываемый при взаимодействии с элементами управления заголовка

Пример расширенной конфигурации:

new TomSelect("#select", {
  plugins: ['dropdown_header'],
  dropdownHeader: {
    title: 'Категории товаров',
    headerClass: 'ts-dropdown-header-custom',
    closeButton: true,
    onClose: () => {
      console.log('Dropdown closed fr om header');
    }
  }
});

DOM-структура и интеграция в dropdown

После инициализации plugin добавляет следующий DOM-элемент:

<div class="ts-dropdown-header">
  <div class="ts-dropdown-header-content">
    <span class="ts-dropdown-header-title">Категории товаров</span>
    <button class="ts-dropdown-header-close"></button>
  </div>
</div>

Этот блок размещается выше контейнера опций (.ts-dropdown-content) и отделяется визуально через CSS-правила.

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

Поведение при открытии и закрытии dropdown

Dropdown Header синхронизируется с жизненным циклом dropdown:

  • при открытии список монтируется или активируется
  • header становится видимым вместе с контейнером
  • при закрытии dropdown header скрывается вместе с ним

Если включена кнопка закрытия, событие клика вызывает метод закрытия основного компонента:

closeButton.addEventListener('click', () => {
  control.close();
});

Таким образом, header может выступать альтернативной точкой управления состоянием dropdown.

Интеграция с поиском и фильтрацией

Tom Select часто использует встроенный search input, который может находиться либо внутри control, либо внутри dropdown. При использовании dropdown header важно учитывать порядок элементов:

  • header
  • search input (если перемещён в dropdown)
  • список результатов

В некоторых конфигурациях header используется как контейнер для search UI:

dropdownHeader: {
  html: `
    <div class="ts-header-wrapper">
      <input type="text" class="ts-header-search" placeholder="Поиск..." />
    </div>
  `
}

В этом случае требуется ручная синхронизация input с внутренним поисковым механизмом Tom Select через API:

const select = new TomSelect("#select", {
  plugins: ['dropdown_header'],
  dropdownHeader: {
    html: '<input class="ts-header-search" placeholder="Поиск">'
  },
  onInitialize() {
    const input = this.dropdown.querySelector('.ts-header-search');

    input.addEventListener('input', (e) => {
      this.setTextboxValue(e.target.value);
      this.refreshOptions();
    });
  }
});

Динамическое обновление заголовка

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

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

Обновление выполняется через прямую модификацию DOM или через API plugin:

const instance = new TomSelect("#select", {
  plugins: ['dropdown_header'],
  dropdownHeader: {
    title: 'Элементы (0 выбрано)'
  }
});

instance.on('change', function() {
  const count = this.items.length;
  const titleEl = this.dropdown.querySelector('.ts-dropdown-header-title');

  if (titleEl) {
    titleEl.textContent = `Элементы (${count} выбрано)`;
  }
});

Такой подход позволяет синхронизировать UI с состоянием модели данных без пересоздания компонента.

Стилизация и кастомизация внешнего вида

CSS-структура dropdown header допускает полную переопределяемость внешнего вида. Основные классы:

  • .ts-dropdown-header
  • .ts-dropdown-header-content
  • .ts-dropdown-header-title
  • .ts-dropdown-header-close

Пример кастомизации:

.ts-dropdown-header {
  padding: 10px;
  border-bottom: 1px solid #ddd;
  background: #fafafa;
}

.ts-dropdown-header-title {
  font-weight: 600;
  font-size: 14px;
}

.ts-dropdown-header-close {
  width: 18px;
  height: 18px;
  cursor: pointer;
}

При необходимости можно полностью заменить layout через html-параметр, что делает систему независимой от стандартной разметки.

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

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

  • “Нет результатов”
  • “Загрузка…”
  • “Фильтр активирован”

Пример динамического изменения:

instance.on('dropdown_open', function() {
  const header = this.dropdown.querySelector('.ts-dropdown-header-title');
  header.textContent = 'Загрузка данных...';
});

instance.on('load', function() {
  const header = this.dropdown.querySelector('.ts-dropdown-header-title');
  header.textContent = 'Доступные элементы';
});

Поведение в множественном выборе

При использовании режима maxItems > 1 dropdown header часто применяется как индикатор состояния:

  • количество выбранных элементов
  • ограничения выбора
  • подсказки по удалению элементов
new TomSelect("#select", {
  maxItems: 5,
  plugins: ['dropdown_header'],
  dropdownHeader: {
    title: 'Можно выбрать до 5 элементов'
  }
});

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

Взаимодействие с другими плагинами

Dropdown Header совместим с большинством встроенных расширений Tom Select:

  • remove_button — отображение кнопок удаления в выбранных элементах
  • clear_button — очистка выбора
  • virtual_scroll — оптимизация больших списков
  • checkbox_options — множественный выбор с чекбоксами

Однако порядок рендера может изменяться в зависимости от набора активных плагинов. Header всегда имеет приоритет размещения выше списка опций.

Производственные особенности и оптимизация

При частом открытии dropdown критически важно избегать повторной генерации header DOM. Tom Select использует кэширование элементов plugin, но при кастомной реализации следует учитывать:

  • минимизацию DOM-операций внутри header
  • избегание тяжёлых вычислений при dropdown_open
  • делегирование событий вместо прямых listener-ов на каждом элементе

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

Поведение при кастомных render-функциях

При переопределении render.option или render.item dropdown header не участвует в процессе рендера, но может быть связан с ними через состояние компонента.

Пример согласованного отображения:

new TomSelect("#select", {
  render: {
    option: function(data, escape) {
      return `<div>${escape(data.text)}</div>`;
    }
  },
  dropdownHeader: {
    title: 'Список опций'
  }
});

Состояние header при этом может зависеть от данных, используемых в render-слое, но не связано напрямую с его жизненным циклом.

Управление через API экземпляра

Tom Select предоставляет доступ к внутренним структурам, что позволяет управлять header программно:

  • доступ через instance.dropdown
  • модификация через querySelector
  • интеграция с событиями open, close, change, load

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

Поведенческая модель компонента

Dropdown Header функционирует как слой представления поверх основной модели данных Tom Select. Его жизненный цикл не влияет на:

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

Он выступает исключительно как UI-надстройка, что обеспечивает предсказуемость поведения и изоляцию логики интерфейса от бизнес-логики компонента.