Свой Select на чистом CSS и JavaScript

Александр Мальцев
Александр Мальцев
28K
39
Свой Select на чистом CSS и JavaScript
Содержание:
  1. Зачем создавать свой Select, если есть <select>
  2. Подключение CSS и JavaScript файлов
  3. Вставка селекта на страницу и его активация
  4. Свойства и методы ItcCustomSelect
  5. Что внутри? Как написан ItcCustomSelect?
  6. Комментарии

В этой статье мы разберём пример реализации кастомного селекта на чистом CSS и JavaScript, который будет очень похож на стандартный HTML-тег <select>.

Зачем создавать свой Select, если есть <select>

Когда мы создаем селект с помощью стандартного HTML-элемента <select>, мы ограничены в его настройке. Так как не всегда можем стилизовать и запрограммировать его так, как нам это нужно.

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

Здесь мы рассмотрим Select, расположенный на GitHub, который называется ItcCustomSelect. Он написан на чистом CSS и JavaScript. ItcCustomSelect имеет простой функционал, который позволяет выбрать одно из нескольких значений в выпадающем списке.

Вот так он выглядит:

Вид селекта, спроектированного на чистом CSS и JavaScript, в закрытом состоянии Вид селекта, спроектированного на чистом CSS и JavaScript, в открытом состоянии

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

Подключение CSS и JavaScript файлов

Исходные коды ItcCustomSelect расположены на GitHub в папке custom-select. ItcCustomSelect - это один из компонентов в наборе ui-components. Там кроме него есть ещё много других, которые вы можете использовать на сайте.

ItcCustomSelect состоит из 2 файлов: itc-custom-select.css и itc-custom-select.js. Скрипт написан на чистом JavaScript и не имеет зависимостей от других плагинов, в том числе и от библиотеки jQuery.

Для его установки необходимо загрузить в своё веб-приложение или сайт 2 этих файла и подключить их:

HTML
<!-- подключаем CSS-селекта -->
<link rel="stylesheet" href="/aasets/css/itc-custom-select.css">
<!-- подключаем JS-селекта -->
<script src="/assets/js/itc-custom-select.js"></script>

CSS подключаем с помощью тега <link>, а JavaScript с помощью <script>.

Вставка селекта на страницу и его активация

Кастомный селект представляет собой класс ItcCustomSelect. Работать с ним можно 2 способами.

Вариант 1. Он подразумевает непосредственную вставку HTML-кода селектора на страницу и его инициализацию с помощью JavaScript как ItcCustomSelect.

В этом варианте необходимо вставить на страницу полный HTML-код селекта, который имеет следующую структуру:

HTML
<!-- Изначально не активна ни одна опция -->
<div class="itc-select" id="select-1">
  <!-- Кнопка для открытия выпадающего списка -->
  <button type="button" class="itc-select__toggle" name="car" value="" data-select="toggle" data-index="-1">Выберите из списка</button>
  <!-- Выпадающий список -->
  <div class="itc-select__dropdown">
    <ul class="itc-select__options">
      <li class="itc-select__option" data-select="option" data-value="volkswagen" data-index="0">Volkswagen</li>
      <li class="itc-select__option" data-select="option" data-value="ford" data-index="1">Ford</li>
      <li class="itc-select__option" data-select="option" data-value="toyota" data-index="2">Toyota</li>
      <li class="itc-select__option" data-select="option" data-value="nissan" data-index="3">Nissan</li>
    </ul>
  </div>
</div>

После вставки HTML-кода его корневой элемент, то есть .itc-select, нужно активировать как ItcCustomSelect посредством JavaScript:

JavaScript
// select-1 – id элемента
const select1 = new ItcCustomSelect('#select-1');

Теперь более подробно про HTML-код. В нём имеется элемент <button>, который используется для переключения видимости выпадающего списка. Действие, которая эта кнопка выполняет, определяется в JavaScript через атрибут data-select="toggle".

У кнопки кроме data-select="toggle" имеются ещё другие атрибуты name и value. Они определяют соответственно имя селекта и его значение. Посредством них, если селект поместить в <form>, его значение вместе с другими данными формы будут отправлены на сервер.

Атрибут data-index содержит индекс выбранной опции. Если по умолчанию не должна быть активна какая-то опция, то value следует задать пустую строку, а data-index – значение -1.

Внутри itc-select__options необходимо расположить необходимые опции. Здесь это осуществляется посредством <li>, к которому необходимо добавить класс itc-select__option и следующие атрибуты:

  • data-select="option" – означает, что это опция;
  • data-value – значение опции;
  • data-index – индекс (порядковый номер) опции.

Если изначально какая-то опция должна быть активна, то к ней необходимо добавить класс itc-select__item_selected. Кроме этого для <button> в атрибут value нужно поместить её значение, в data-index – её индекс, а в содержимое – её контент.

Пример HTML-кода, в котором первая опция установлена по дефолту:

HTML
<!-- по дефолту активна 1 опция -->
<div class="itc-select" id="select-1">
  <button type="button" class="itc-select__toggle" name="car" value="ford" data-select="toggle" data-index="1">Выберите из списка</button>
  <div class="itc-select__dropdown">
    <ul class="itc-select__options">
      <li class="itc-select__option" data-select="option" data-value="volkswagen" data-index="0">Volkswagen</li>
      <li class="itc-select__option select__option_selected" data-select="option" data-value="ford" data-index="1">Ford</li>
      <li class="itc-select__option" data-select="option" data-value="toyota" data-index="2">Toyota</li>
      <li class="itc-select__option" data-select="option" data-value="nissan" data-index="3">Nissan</li>
    </ul>
  </div>
</div>

Вариант 2. Этот вариант предполагает вставку в HTML пустого элемента <div>, который следует использовать в качестве селекта. То есть в этом случае HTML-код будет следующим:

HTML
<div id="select-2"></div>

В этом варианте всю структуру создаст сам JavaScript. Варианты и дефолтный текст селекту необходимо передать при создании экземпляра класса ItcCustomSelect посредством аргумента в формате объекта:

JavaScript
const select2 = new ItcCustomSelect('#select-2', {
  name: 'car', // значение атрибута name у кнопки
  targetValue: 'ford', // значение по умолчанию
  options: [['volkswagen', 'Volkswagen'], ['ford', 'Ford'], ['toyota', 'Toyota'], ['nissan', 'Nissan']], // опции
});

Значение options – это массив массивов. Первый элемент массива – это значение опции, а второй – её текстовое представление.

Если не нужно чтобы селект имел значение по умолчанию, то установите ключу targetValue пустую строку или вообще его не указывайте:

JavaScript
const select2 = new ItcCustomSelect('#select-2', {
  name: 'car', // значение атрибута name у кнопки
  options: [['volkswagen', 'Volkswagen'], ['ford', 'Ford'], ['toyota', 'Toyota'], ['nissan', 'Nissan']], // опции
});

Свойства и методы ItcCustomSelect

После инициализации селекта, нам будут доступны следующие свойства и методы:

  • value – позволяет как получить выбранную опцию, так и установить её;
  • selectedIndex – индекс выбранного элемента (нумерация начинается с 0);
  • show() – показывает выпадающий список с опциями;
  • hide() – скрывает dropdown меню;
  • toggle() – переключает видимость выпадающего меню;
  • dispose() – удаляет обработчики событий, связанных с этим селектом.

Использование свойства value:

JavaScript
// установим в качестве выбранной опции элемент со значением toyota
select2.value = 'toyota';
// получим значение выбранной опции
console.log(select2.value); // toyota

Кроме этого value позволяет также сбросить выбранную опцию. Для этого value нужно установить пустую строку или значение не соответствующее ни одной из опций:

JavaScript
// сбросим выбранную опцию
select2.value = '';

Использование свойства selectedIndex:

JavaScript
// установим в качестве выбранной опции элемент с индексом 2
select2.selectedIndex = 2;
// получим индекс выбранной опции
console.log( select2.selectedIndex );

Если ни один из элементов не выбран, то selectedIndex возвращает -1:

JavaScript
select2.value = '';
// получим индекс выбранного элемента
console.log( select2.selectedIndex ); // -1

Сбросить выбранный элемент можно не только посредством value, но также, если установить selectedIndex число -1 или индекс элемента, которого нет:

JavaScript
select2.selectedIndex = -1;

Если нам необходимо выполнить некоторые действия при выборе элемента отличного от текущего, то мы можем воспользоваться событием itc.select.change, генерируемым в JavaScript коде:

JavaScript
document.querySelector('#select-2').addEventListener('itc.select.change', (e) => {
  const btn = e.target.querySelector('.itc-select__toggle');
  // выбранное значение
  console.log(`Выбранное значение: ${btn.value}`);
    // индекс выбранной опции
  console.log(`Индекс выбранной опции: ${btn.dataset.index}`);
  // выбранный текст опции
  const selected = e.target.querySelector('.itc-select__option_selected');
  const text = selected ? selected.textContent : '';
  console.log(`Выбранный текст опции: ${text}`);
});

Кроме как использовать событие, это действие также можно выполнить с помощью метода onSelected при создании экземпляра объекта ItcCustomSelect:

2 способ (через метод onSelect):

JavaScript
new ItcCustomSelect('#select-2', {
  name: 'car',
  targetValue: 'ford',
  data: [['volkswagen', 'Volkswagen'], ['ford', 'Ford'], ['toyota', 'Toyota'], ['nissan', 'Nissan']],
  onSelected(select, option) {
    // выбранное значение
    console.log(`Выбранное значение: ${itc.select.value}`);
    // индекс выбранной опции
    console.log(`Индекс выбранной опции: ${select.selectedIndex}`);
    // выбранный текст опции
    const text = option ? option.textContent : '';
    console.log(`Выбранный текст опции: ${text}`);
  }
});

Что внутри? Как написан ItcCustomSelect?

Компонент Select построен с использованием HTML, CSS и JavaScript. Его HTML-код мы уже рассматривали. Он имеет следующую структуру:

HTML
<div class="itc-select">
  <button type="button" class="itc-select__toggle" name="car" value="" data-select="toggle" data-index="-1">Выберите из списка</button>
  <div class="itc-select__dropdown">
    <ul class="itc-select__options">
      <li class="itc-select__option" data-select="option" data-value="volkswagen" data-index="0">Volkswagen</li>
      <li class="itc-select__option elect__option_selected" data-select="option" data-value="ford" data-index="1">Ford</li>
      <li class="itc-select__option" data-select="option" data-value="toyota" data-index="2">Toyota</li>
    </ul>
  </div>
</div>

Элемент с классом itc-select является корневым. В нём находится вся HTML-структура селекта. Тег <button> с классом itc-select__toggle предназначен для отображения выбранного значения опции и переключения видимости выпадающего списка. Само выпадающее меню реализовано через элемент .itc-select__dropdown. Оно с помощью CSS настраивается так, чтобы оно было расположено под <button>. Список вариантов .itc-select__options организован посредством маркированного списка. Выбранный элемент в нём отмечается посредством добавления к нему класса itc-select__option_selected.

Этот HTML-кода не обязательно создавать вручную на странице. Имеется также автоматический вариант его создания с помощью JavaScript. В этом случае как уже было отмечено выше нужно лишь на страницу поместить пустой элемент <div>.

Затем необходимо активировать его с помощью JavaScript как ItcCustomSelect. На этом с HTML-кодом всё.

Классы будем использовать в CSS для добавления к элементам стилей, а data-атрибуты – в JavaScript.

CSS-код компонента Select можно посмотреть на GitHub.

Для элемента, выступающего в качестве обёртки установлено относительное позиционирование. Это необходимо для того, чтобы выпадающее меню можно было позиционировать относительно его.

CSS
.itc-select {
  position: relative;
  ...
}

Элемент .itc-select__toggle стилизуем как кнопку. Текущий вариант селекта будем выводить как её содержимое:

CSS
.itc-select__toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 0.375rem 0.75rem;
  font-size: 1rem;
  font-style: italic;
  line-height: 1.4;
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 0.3125rem;
  cursor: pointer;
  user-select: none;
}

Иконку к кнопке добавим через псевдоэлемент ::after:

CSS
.itc-select__toggle::after {
  flex-shrink: 0;
  width: 0.75rem;
  height: 0.75rem;
  margin-left: 1rem;
  background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" height="100" width="100"%3E%3Cpath d="M97.625 25.3l-4.813-4.89c-1.668-1.606-3.616-2.41-5.84-2.41-2.27 0-4.194.804-5.777 2.41L50 52.087 18.806 20.412C17.223 18.805 15.298 18 13.03 18c-2.225 0-4.172.804-5.84 2.41l-4.75 4.89C.813 26.95 0 28.927 0 31.23c0 2.346.814 4.301 2.439 5.865l41.784 42.428C45.764 81.174 47.689 82 50 82c2.268 0 4.215-.826 5.84-2.476l41.784-42.428c1.584-1.608 2.376-3.563 2.376-5.865 0-2.26-.792-4.236-2.375-5.932z"/%3E%3C/svg%3E');
  background-size: cover;
  content: "";
}

По умолчанию dropdown меню не будет показываться. Включение его отображения будем осуществлять посредством добавления к нему класса itc-select_show:

CSS
.itc-select_show .itc-select__dropdown {
  display: block;
}

При этом при показе dropdown меню иконку будем поворачивать на 180 градусов посредством CSS-трансформации:

CSS
.itc-select_show .itc-select__toggle::after {
  transform: rotate(180deg);
}

CSS-код для стилизации dropdown меню:

CSS
.itc-select__dropdown {
  position: absolute;
  top: 2.5rem;
  right: 0;
  left: 0;
  z-index: 2;
  display: none;
  max-height: 10rem;
  overflow-y: auto;
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 0.3125rem;
}
.itc-select__options {
  margin: 0;
  padding: 0;
  list-style: none;
}
.itc-select__option {
  padding: 0.375rem 0.75rem;
}

Стилизация при наведении на пункт меню:

CSS
.itc-select__option:hover {
  background-color: #f5f5f5;
  cursor: pointer;
  transition: 0.2s background-color ease-in-out;
}

JavaScript код компонента доступен на GitHub. Его можно открыть, используя эту ссылку.

Код написан в виде класса ItcCustomSelect:

JavaScript
class ItcCustomSelect {
  ...
}

Свойства и методы, которые не нужно использовать вне класса, начинаются с нижнего подчеркивания:

JavaScript
class ItcCustomSelect {
  constructor(target, params) {
    this._el = typeof target === 'string' ? document.querySelector(target) : target;
    ...
  }
  ...
  _onClick(e) { ... }
  ...
}

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

Структура JavaScript кода:

class ItcCustomSelect {
  // статический метод для создания HTML-кода селекта
  static template(params) { }
  // для закрытия открытого селекта при клике вне его
  static hideOpenSelect() { }
  // конструктор
  constructor(target, params) { }
  // обработчик события click
  _onClick(e) { }
  // обновляет значения атрибутов в зависимости от выбранной опции, генерирует событие 'itc.elect.change'
  _updateOption(el) { }
  // сбрасывает состояние, генерирует событие 'itc.select.change'
  _reset() { }
  // при изменении выбранной опции
  _changeValue(option) { }
  // включает отображение выпадающего списка
  show() { }
  // скрывает список с опциями
  hide() { }
  // переключает список с опциями
  toggle() { }
  // удаления слушателей события click селекта
  dispose() { }
  // геттер, который возвращает значение выбранной опции
  get value() { }
  // сеттер, который позволяет установить опцию по значению
  set value(value) { }
  // геттер, который возвращает индекс выбранной опции
  get selectedIndex() { }
  // сеттер, который позволяет выбрать опцию по её индексу
  set selectedIndex(index) { }
}

ItcCustomSelect.hideOpenSelect();

Комментарии: 39

  1. ViktarStasela
    ViktarStasela
    2022-08-24 22:00:04
    Добрый день, Александр. Использовал ваш кастомный селект в проекте. В проекте несколько страниц, и на разных страницах используются разные селеткты. Все они инициализируются в одном файле и все замечательно работает. Но есть один нюанс. Заключается он в том, что если на страница отсутсвует разметка под селект (он просто не предусмотрен на этой странице), но он инициализируется для другой страницы, он вступает в конфликт с swiper (https://swiperjs.com/) и отключает его. Если в разметке страницы присутствуют все селекты, которые инициализированы в js, то swiper работает замечательно. Подскажите, с чем это может быть связано и как решить?
    Спасибо!
  1. ViktarStasela
    ViktarStasela
    2022-08-25 10:20:15
    Даже отключает не только swiper, но и все сторонние бандлы.
  • Александр Мальцев
    Александр Мальцев
    2022-08-25 15:38:23
    Привет, посмотрю в ближайшее время.
  • Александр Мальцев
    Александр Мальцев
    2022-08-28 12:36:36
    1. Можно перед тем, как инициализировать элемент как селект проверить, а существует ли этот элемент на странице:
    const el = document.querySelector('#select-1');
    if (el) {
      new ItcCustomSelect(el);
    }
    2. На GitHub добавил статический метод create. Он проверяет наличие элемента на странице, и если он имеется, то активирует его как ItcCustomSelect:
    ItcCustomSelect.create('#select-1');
    Также немного обновил код селекта на Github и текст статьи. В рамках ребрединга переименовал его в ItcCustomSelect.
  • ViktarStasela
    ViktarStasela
    2022-08-28 18:29:11
    Спасибо!
  • cushhy
    cushhy
    2022-04-30 23:07:41
    Доброго времени, спасибо за данный селект, но я начинающий, и вообще не разбираюсь в JS. Прошу помогите мне) У меня на сайте есть калькулятор, состоит он из ползунка, который дает выбрать площадь( сайт по натяжке потолков ), далее идет три селекта, материал, количество люстр, и количество ламп. Вот мне нужно сделать калькулятор, чтобы при выборе опции из селекта, стоимость сразу шла в общую и суммировалась( а еще нужно чтобы площадь умножалась на стоимость материала ), как это сделать я понимаю на словах, но отобразить в коде не могу(. Я буду примерно благодарен, если поможете, заранее спасибо))) Если потребуется код, прислать смогу.
    1. agat
      agat
      2022-04-25 18:16:41
      Здравствуйте, Александр! Очень классная статья! Спасибо)
      Подскажите, как добавить обработчик события по клику на выбираемый элемент выпадающего списка?

      Моя задача — сделать так, чтобы при клике на выбранный элемент выпадающего списка открывался соответствующий таб. Функцию открытия соответствующего таба я написал, а вот как теперь привязать элемент списка к табу… пока не знаю…
      1. Александр Мальцев
        Александр Мальцев
        2022-04-26 10:12:34
        Здравствуйте! Спасибо!
        Для этого можно использовать событие select.change:
        document.querySelector('.select').addEventListener('select.change', (e) => {
          // ...
        }
      2. agat
        agat
        2022-04-26 10:45:12
        Спасибо! Буду пробовать)
    2. Heitz
      Heitz
      2022-01-30 20:06:17
      Сколько же соплей летело по стенам, когда я месяц делал свой первый кастомный селект )… потом загуглил и нащёл это ) и вся боль в том, что он похож на мой практически идеально, вплодь до названия css классов…
      1. Myshynov
        Myshynov
        2022-01-22 11:07:44
        Здраствуйте Александр! Спасибо вам за проделанную работу. Отличная реализация кастомных селектов!

        У меня возникла небольшая проблема.
        Дело в том что в моём списке используются стили и обвертки в «span». Если назначить одну из опций по умолчанию то всё ОК и спаны с классами и стилями выводятся в кнопку. Но как только выбираешь из списка другую опцию в кнопке отображается строка без «span».
        Вот пример кода чтобы вам было проще меня понять

        const registrationSelect = new CustomSelect('#registration-select', {
          name: 'registration', // значение атрибута name у кнопки
          targetValue: 'RegularRegistration', // значение по умолчанию
          options: [
            ['RegularRegistration', 'Regular Registration <span class="price">($35.00)</span> <span class="sub-name">Breakfast pastries and refreshments included</span>'],
            ['RegularRegistration2', '2Regular Registration <span class="price">($35.00)</span> <span class="sub-name">Breakfast pastries and refreshments included</span>'],
            ['RegularRegistration3', '3Regular Registration <span class="price">($35.00)</span> <span class="sub-name">Breakfast pastries and refreshments included</span>'],
            ['RegularRegistration4', '4Regular Registration <span class="price">($35.00)</span> <span class="sub-name">Breakfast pastries and refreshments included</span>']
          ], // опции
        });
        1. Myshynov
          Myshynov
          2022-01-22 11:29:00
          Я 2 дня не находил себе места перечитывал статью и все комментарии.
          И как только я написал вопрос я нашел путь к ответу. Если вдруг кто-то столкнется с таким же вопросом то вот решение. Найди верхнюю строку и замени в ней .textContent на .innerHTML:
          this._elToggle.textContent = option.textContent;
          this._elToggle.innerHTML = option.innerHTML;
          Только заметил что в самом вопросе не отобразились «span». они у меня были в значении «options»
        2. Александр Мальцев
          Александр Мальцев
          2022-01-23 14:20:27
          Привет! Спасибо за отзыв! Рад, что кастомный селект понравился.
          Необходимо добавить ещё в начало метода _update следующую строчку (на Github обновил этот момент):
          _update(option) {
            option = option.closest('.select__option'); // добавить эту строчку
            // ...
          }
      2. Юрий
        Юрий
        2021-12-04 15:43:01
        Здравствуйте, спасибо за плагин!!!
        Столкнулся с несколькими проблемами.
        Проект разрабатываю на Laravel.
        Первая проблема — при отправке данных на бэк, данные селектов не приходят, несмотря на наличие атрибута name и значения, но эту проблему обошел путем добавления hidden input и дальнейшего добавления в него выбранных данных при помощи js.
        Вторая проблема — есть форма с двумя селектами, которая заполняется пользователем поэтапно. Есть кнопки prev и next, при нажатии next блок с первым селектом (data-block=«1») скрывается и ajax-запросом получаются подкатегории выбранной в первом блоке категории, и на основании ответа во втором блоке (data-block=«2») создается новый селект с подкатегориями, после чего отображается второй блок.

        html код
        
        <div class="form-group" data-block="1">
                                <div class="select" id="category-select">
                                    <button type="button" class="select__toggle" id="category_id-btn" name="category_id-btn" value=""
                                            data-select="toggle" data-index="-1">
                                        Выберите категорию
                                    </button>
                                    <div class="select__dropdown">
                                        <ul class="select__options">
                                            @php $index = 0; @endphp
                                            @foreach($categories as $category)
                                                <li class="select__option" data-select="option" data-value="{{ $category->id }}"
                                                    data-index="{{ $index++ }}">{{ $category->name }}</li>
                                            @endforeach
                                        </ul>
                                    </div>
                                </div>
                                <input type="hidden" name="category_id" id="category_id">
                            </div>
                            <div class="form-group" data-block="2">
                                <div class="select" id="service-select"></div>
                                <input type="hidden" name="service_id" id="service_id">
                            </div>
        


        js код
        
        let serviceSelect = new CustomSelect('#service-select', {
                                            name: 'service_id-btn',
                                            options
                                        });
        
        Суть проблемы — при первом отображении второго селекта все работает, но когда нажимаю кнопку prev, скрываю второй селект, перехожу на первый, выбираю новую категорию и перехожу обратно на второй селект, html код с новыми подкатегориями формируется, НО при клике на селект не открывается дропдаун с подкатегориями, если еще раз вернусь назад, выбираю другую категорию, и перехожу снова на второй селект, дропдаун уже открывается, но при выборе нужной подкатегории он уже не закрывается.
        1. Александр Мальцев
          Александр Мальцев
          2021-12-07 15:17:34
          Привет!
          Вот пример состоящий из 2 селектов. Может он поможет. В нём при выборе элемента из 1 селекта, второй наполняется данными посредством AJAX в зависимости от значения первого селекта.
      3. Gregory
        Gregory
        2021-11-01 15:54:51
        1 — поставьте пожалуйста кнопку для комментария в начале списка комментариев, а то пригодится листать в самый низ списка комментов
        2 — в начале скрипта вы определяете константы вне класса, вне конструктора. Это для каких целей делается?
        1. Gregory
          Gregory
          2021-11-01 12:13:01
          Небольшая модификация CSS для мобильных — может пригодится

          @media (max-width: 500px) {
            .select__options{
              position: fixed;
              height: 100%;
              overflow-y: scroll;
              top: 0;
              left: 0;
              background: white;
              width: 100vw;
              padding: 20px;
            }
          }
          1. Gregory
            Gregory
            2021-11-01 12:28:28
            да вот ещё
            
            * {
                  box-sizing: border-box;
            }
            
        2. Александр
          Александр
          2021-10-14 12:46:27
          Александр, добрый день. Имеется ли возможность задавать разные значения переменной
          selectedContent
          для разных селектов. По умолчанию стоит 'Выберите из списка';
          1. Daniel
            Daniel
            2021-09-29 10:04:56
            Здраствуйте Александр. Большое спасибо за разработанный плагин CustomSelect, отличная работа. сэкономлено кучу времени. У меня возник один вопрос: на базе вашего плагина пишу калькулятор и столкнулся с небольшой проблемой, а именно: создаю функцию Reset для сброса всех значений «name», «value» в дефолтное состояние но при клике на кнопке reset не получаю никакого результата.
            Вот пример кода:
            function resetBtn() {
              let btnReset = document.queryselectorAll("select-reset");
              btnReset.value = "" ;
              btnRest. name = "" ;
            };
            <button type="reset" onClick="resetBtn()">Reset</button>
            Буду очень благодарен за помощь. Спасибо.
            1. Александр Мальцев
              Александр Мальцев
              2021-09-29 14:20:23
              Добрый день! Наверно так:
              function resetBtn() {
                let btnReset = document.querySelectorAll('.select-reset');
                btnReset.forEach((element) => {
                  element.value = '';
                  element.name = '';
                });
              }
              Не знаю, что такое select-reset? Класс?
              После того как выбрали элементы с помощью querySelectorAll, их нужно перебрать, например, с помощью forEach. Так напрямую нельзя.
            2. Daniel
              Daniel
              2021-09-29 14:46:22
              Большое спасибо за столь быстрый ответ. да, select-reset это я добавил некий клас, для сброса значений и в калькуляторе я использую несколько CustomSelect и радио-кнопки checkbox. ok, попробую с forEach. Ещё раз спасибо. Хорошего дня
          2. Daria
            Daria
            2021-08-20 18:19:04
            Здравствуйте, Александр, спасибо вам за проделанную работу, ваш селект прекрасен))

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

            1) Кликаем на первый селект, ничего, не выбрано, кликаем, на второй селект, первый остается в открытом состоянии, но не активен при ховере, если кликнуть «оживает», получается два открытых одновременно селекта.

            При этом в обратном порядке работает правильно
            2) Кликаем второй селект, кликаем на первый второй закрыватся при клике на первый.

            1. Александр Мальцев
              Александр Мальцев
              2021-08-21 12:04:30
              Привет! Спасибо за отзыв. Переписал код компонента, а также исправил этот баг. Также изменил название классов и атрибутов, поэтому обратите на это внимание при обновлении кода.
          3. Кирилл
            Кирилл
            2021-08-18 18:13:03
            Верно ли понимаю, что мы можем управлять выбором значения по индексу или названию(value), так:
            select1.selectedItem(6); // (где 6 — это 7 элемент списка).
            Но у меня к сожалению, так не сработало :(

            P.S. спасибо большое за реализацию.
            1. Александр Мальцев
              Александр Мальцев
              2021-08-19 03:34:19
              Нужно передавать в формате объекта:
              // по индексу
              select1.selectedItem({index: 0})
              // по значению
              select1.selectedItem({value: 'Nissan'})
            2. Кирилл
              Кирилл
              2021-08-19 09:37:00
              Благодарю!
          4. Konstantin
            Konstantin
            2021-06-03 13:35:58
            Может быть это у меня что то с ip, но ни одна ссылка на материалы из этого поста не открывается. Выдает 404 ошибку. в том числе на GIT!!!
            1. Александр Мальцев
              Александр Мальцев
              2021-06-03 13:50:48
              Поправил ссылки.
          5. Александр
            Александр
            2020-11-24 17:07:03
            Александр, здравствуйте! Спасибо, за отличный вариант и достойную альтернативу дефолтному селекту. Пытаюсь это решение использовать в сортировке mFilter2, не получается всё сделать по уму да и вообще мало что получается честно говоря, делаю так:

            <div class="select" id="mse2_sort">
              <div class="select__backdrop" data-select="backdrop"></div>
              
             <button type="button" class="select__trigger" data-select="trigger" value="asc" data-sort="resource|pagetitle" data-icon="fa-list">
                По умолчанию
             </button>
            
            <div class="select__dropdown">
                <ul class="select__items">
                  <li class="select__item" data-select="item"  value="asc" data-sort="extendresource|date"><i class="fa fa-play"></i>Дата</li>
                  <li class="select__item" data-select="item" value="desc" data-sort="extendresource|size"><i class="fa fa-table"></i>Размер</li>
                </ul>
              </div>
            </div>
            <script>
             const select1 = new CustomSelect('#mse2_sort'); 
            </script>
            как я понимаю, так работать не будет, так как в файле default.js в параметрах скрипта mFilter2, завязано всё на теге «a»
            sort_link: '#mse2_sort a'
            если изменить на тег «li», то сортировка начинает работать, но не сохраняет выбранное значение при перезагрузке страницы. Александр, если возможно расскажите пожалуйста как нужно и лучше сделать, чтобы сортировка работала и сохраняла выбранное значение при перезагрузки страницы?
            1. Александр Мальцев
              Александр Мальцев
              2020-11-26 16:53:06
              Привет! Спасибо за отзыв.
              Чтобы в mFilter2 изменить sort_link можно использовать параметр &filterOptions:
              [[!mFilter2? 
                ...
                &filterOptions=`{"sort_link": "#mse2_sort li"}`
              ]]
              Установить выбранную сортировку в CustomSelect после перезагрузки страницы можно посредством добавления следующего скрипта на страницу:
              <script>
              const queryString = window.location.search;
              const urlParams = new URLSearchParams(queryString);
              const sort = urlParams.get('sort');
              let value = '';
              if (sort) {
                const delim = sort.indexOf(':');
                const res = delim === -1 ? sort : sort.substring(0, delim);
                const $li = document.querySelector(`#mse2_sort li[data-sort="${res}"]`);
                if ($li) {
                  value = $li.textContent;
                }
              }
              const select1 = new CustomSelect('#mse2_sort');
              if (value) {
                select1.selectedItem({value: value})
              } 
              </script>
            2. Александр
              Александр
              2020-11-26 20:20:29
              Александр, огромное спасибо за решение, в очередной раз выручили.
          6. Владимир
            Владимир
            2020-11-07 23:40:57
            Александр, еще момент.

            1. Александр Мальцев
              Александр Мальцев
              2020-11-08 07:28:55
              Спасибо! Этот момент тоже доработал и обновил код js-файла на Github.
          7. Владимир
            Владимир
            2020-11-07 15:03:22
            Еще момент.
            Если создание нового экземпляра объекта CustomSelect происходит таким образом
            const select1 = new CustomSelect(".select");
            то в консоли получаю следующую ошибку
            1. Александр Мальцев
              Александр Мальцев
              2020-11-07 15:47:16
              Спасибо! Поправил код скрипта на Github.
          8. Владимир
            Владимир
            2020-11-07 14:58:00
            Добрый день!

            На странице категории есть сортировка, сделанная через стандартный select. При выборе какой-либо сортировки происходит перезагрузка страницы.

            Пытаюсь применить Ваш плагин. В итоге код получился такой
            <div class="select">
              <div class="select__backdrop" data-select="backdrop"></div>
              <button type="button" class="select__trigger" data-select="trigger">По умолчанию</button>
              <div class="select__dropdown">
                <ul class="select__items">
                  <?php foreach ($sorts as $sorts) { ?>
                  <?php if ($sorts['value'] == $sort . '-' . $order) { ?>
                  <li class="select__item select__item_selected" data-select="item" data-url="<?php echo $sorts['href']; ?>"><?php echo $sorts['text']; ?></li>
                  <?php } else { ?>
                  <li class="select__item" data-select="item" data-url="<?php echo $sorts['href']; ?>"><?php echo $sorts['text']; ?></li>
                  <?php } ?>
                  <?php } ?>
                </ul>
              </div>
            </div>
            <script>
            const select1 = new CustomSelect(".select", { });
            
            document.querySelector(".select").addEventListener("select.change", (e) => {
              location = document.querySelector(".select__item_selected").getAttribute("data-url"); 
            });
            </script>
            Не получается подставить выбранное значение в button.
            Подскажите, пожалуйста, как это можно сделать?
            1. Александр Мальцев
              Александр Мальцев
              2020-11-07 15:36:20
              Здравствуйте!
              Установите выбранное значение в button с помощью JavaScript:
              document.querySelector('.select__trigger').textContent = document.querySelector('.select__item_selected').textContent;
              
            2. Владимир
              Владимир
              2020-11-07 16:01:39
              Оказалось все так просто.
              Спасибо, Александр!