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

Александр Мальцев
Александр Мальцев
32K
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
    24.08.2022, 22:00
    Добрый день, Александр. Использовал ваш кастомный селект в проекте. В проекте несколько страниц, и на разных страницах используются разные селеткты. Все они инициализируются в одном файле и все замечательно работает. Но есть один нюанс. Заключается он в том, что если на страница отсутсвует разметка под селект (он просто не предусмотрен на этой странице), но он инициализируется для другой страницы, он вступает в конфликт с swiper (https://swiperjs.com/) и отключает его. Если в разметке страницы присутствуют все селекты, которые инициализированы в js, то swiper работает замечательно. Подскажите, с чем это может быть связано и как решить?
    Спасибо!
    1. ViktarStasela
      ViktarStasela
      25.08.2022, 10:20
      Даже отключает не только swiper, но и все сторонние бандлы.
    2. Александр Мальцев
      Александр Мальцев
      25.08.2022, 15:38
      Привет, посмотрю в ближайшее время.
    3. Александр Мальцев
      Александр Мальцев
      28.08.2022, 12:36
      1. Можно перед тем, как инициализировать элемент как селект проверить, а существует ли этот элемент на странице:
      const el = document.querySelector('#select-1');
      if (el) {
        new ItcCustomSelect(el);
      }
      2. На GitHub добавил статический метод create. Он проверяет наличие элемента на странице, и если он имеется, то активирует его как ItcCustomSelect:
      ItcCustomSelect.create('#select-1');
      Также немного обновил код селекта на Github и текст статьи. В рамках ребрединга переименовал его в ItcCustomSelect.
    4. ViktarStasela
      ViktarStasela
      28.08.2022, 18:29
      Спасибо!
  2. cushhy
    cushhy
    30.04.2022, 23:07
    Доброго времени, спасибо за данный селект, но я начинающий, и вообще не разбираюсь в JS. Прошу помогите мне) У меня на сайте есть калькулятор, состоит он из ползунка, который дает выбрать площадь( сайт по натяжке потолков ), далее идет три селекта, материал, количество люстр, и количество ламп. Вот мне нужно сделать калькулятор, чтобы при выборе опции из селекта, стоимость сразу шла в общую и суммировалась( а еще нужно чтобы площадь умножалась на стоимость материала ), как это сделать я понимаю на словах, но отобразить в коде не могу(. Я буду примерно благодарен, если поможете, заранее спасибо))) Если потребуется код, прислать смогу.
  3. agat
    agat
    25.04.2022, 18:16
    Здравствуйте, Александр! Очень классная статья! Спасибо)
    Подскажите, как добавить обработчик события по клику на выбираемый элемент выпадающего списка?

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

    У меня возникла небольшая проблема.
    Дело в том что в моём списке используются стили и обвертки в «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
      22.01.2022, 11:29
      Я 2 дня не находил себе места перечитывал статью и все комментарии.
      И как только я написал вопрос я нашел путь к ответу. Если вдруг кто-то столкнется с таким же вопросом то вот решение. Найди верхнюю строку и замени в ней .textContent на .innerHTML:
      this._elToggle.textContent = option.textContent;
      this._elToggle.innerHTML = option.innerHTML;
      Только заметил что в самом вопросе не отобразились «span». они у меня были в значении «options»
    2. Александр Мальцев
      Александр Мальцев
      23.01.2022, 14:20
      Привет! Спасибо за отзыв! Рад, что кастомный селект понравился.
      Необходимо добавить ещё в начало метода _update следующую строчку (на Github обновил этот момент):
      _update(option) {
        option = option.closest('.select__option'); // добавить эту строчку
        // ...
      }
  6. Юрий
    Юрий
    04.12.2021, 15:43
    Здравствуйте, спасибо за плагин!!!
    Столкнулся с несколькими проблемами.
    Проект разрабатываю на 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. Александр Мальцев
      Александр Мальцев
      07.12.2021, 15:17
      Привет!
      Вот пример состоящий из 2 селектов. Может он поможет. В нём при выборе элемента из 1 селекта, второй наполняется данными посредством AJAX в зависимости от значения первого селекта.
  7. Gregory
    Gregory
    01.11.2021, 15:54
    1 — поставьте пожалуйста кнопку для комментария в начале списка комментариев, а то пригодится листать в самый низ списка комментов
    2 — в начале скрипта вы определяете константы вне класса, вне конструктора. Это для каких целей делается?
  8. Gregory
    Gregory
    01.11.2021, 12:13
    Небольшая модификация 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
      01.11.2021, 12:28
      да вот ещё
      
      * {
            box-sizing: border-box;
      }
      
  9. Александр
    Александр
    14.10.2021, 12:46
    Александр, добрый день. Имеется ли возможность задавать разные значения переменной
    selectedContent
    для разных селектов. По умолчанию стоит 'Выберите из списка';
  10. Daniel
    Daniel
    29.09.2021, 10:04
    Здраствуйте Александр. Большое спасибо за разработанный плагин 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. Александр Мальцев
      Александр Мальцев
      29.09.2021, 14:20
      Добрый день! Наверно так:
      function resetBtn() {
        let btnReset = document.querySelectorAll('.select-reset');
        btnReset.forEach((element) => {
          element.value = '';
          element.name = '';
        });
      }
      Не знаю, что такое select-reset? Класс?
      После того как выбрали элементы с помощью querySelectorAll, их нужно перебрать, например, с помощью forEach. Так напрямую нельзя.
    2. Daniel
      Daniel
      29.09.2021, 14:46
      Большое спасибо за столь быстрый ответ. да, select-reset это я добавил некий клас, для сброса значений и в калькуляторе я использую несколько CustomSelect и радио-кнопки checkbox. ok, попробую с forEach. Ещё раз спасибо. Хорошего дня
  11. Daria
    Daria
    20.08.2021, 18:19
    Здравствуйте, Александр, спасибо вам за проделанную работу, ваш селект прекрасен))

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

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

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

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

    P.S. спасибо большое за реализацию.
    1. Александр Мальцев
      Александр Мальцев
      19.08.2021, 03:34
      Нужно передавать в формате объекта:
      // по индексу
      select1.selectedItem({index: 0})
      // по значению
      select1.selectedItem({value: 'Nissan'})
    2. Кирилл
      Кирилл
      19.08.2021, 09:37
      Благодарю!
  13. Konstantin
    Konstantin
    03.06.2021, 13:35
    Может быть это у меня что то с ip, но ни одна ссылка на материалы из этого поста не открывается. Выдает 404 ошибку. в том числе на GIT!!!
    1. Александр Мальцев
      Александр Мальцев
      03.06.2021, 13:50
      Поправил ссылки.
  14. Александр
    Александр
    24.11.2020, 17:07
    Александр, здравствуйте! Спасибо, за отличный вариант и достойную альтернативу дефолтному селекту. Пытаюсь это решение использовать в сортировке 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. Александр Мальцев
      Александр Мальцев
      26.11.2020, 16:53
      Привет! Спасибо за отзыв.
      Чтобы в 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. Александр
      Александр
      26.11.2020, 20:20
      Александр, огромное спасибо за решение, в очередной раз выручили.
  15. Владимир
    Владимир
    07.11.2020, 23:40
    Александр, еще момент.

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

    На странице категории есть сортировка, сделанная через стандартный 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. Александр Мальцев
      Александр Мальцев
      07.11.2020, 15:36
      Здравствуйте!
      Установите выбранное значение в button с помощью JavaScript:
      document.querySelector('.select__trigger').textContent = document.querySelector('.select__item_selected').textContent;
      
    2. Владимир
      Владимир
      07.11.2020, 16:01
      Оказалось все так просто.
      Спасибо, Александр!