Как сделать выпадающий список с возможность ввода, как в input type="text" и возможностью выбора, как в select

Нужен похожий выпадающий список, в котором совмещен функционал input type="text" и select. Как можно такой реализовать? Вариант с datalist не подходит, так как он работает по подсказкам и при вводе допустим значения "2" все варианты без двойки пропадают, но пропадать они не должны.

введите сюда описание изображения

введите сюда описание изображения


Ответы (2 шт):

Автор решения: ksa

Могу предложить некий "упрощенный" вариант такого "селекта"...

document.querySelectorAll('.select').forEach(el => {
  el.addEventListener('click', e => {
    if (e.target.tagName === 'BUTTON') {
      el.querySelector('ul').classList.toggle('on')
    }
    if (e.target.tagName === 'LI') {
      el.querySelector('input').value = e.target.textContent
      el.querySelector('ul').classList.remove('on')
    }
  })
})
.select {
  display: inline-block;
}
.select ul {
  display: none;
  border: 1px solid;
  list-style-type: none;
  list-style-position: outside;
}
.select ul.on {
  display: block;
}
<div class='select'>
  <div>
    <input />
    <button>+</button>
  </div>
  <ul>
    <li>10</li>
    <li>20</li>
    <li>30</li>
  </ul>
</div>

→ Ссылка
Автор решения: Miha

const search = document.getElementById('input-search');
const list = document.getElementById('search-list');
const options = list.children;

for (let i = 1, n = options.length; i < n; i++) {
  let option = options[i];

  option.addEventListener('click', (e) => {
    search.value = e.target.textContent;
  })
}

// При фокусе инпута показывает писок
search.addEventListener('focus', (e) => {
  searchFromInput(e.target.value);
});

// При расфокусировать инпута скрываем select
search.addEventListener('focusout', () => {
  changeSelectSize(1);
});

// Добавляем эвент при нажатия на клавиши
search.addEventListener('keyup', (e) => {
  searchFromInput(e.target.value);
})

function changeSelectSize(size) {
  setTimeout(() => {
    list.size = size;
  }, 75);
}

// Проходим по каждому элементу списка
function searchFromInput(value) {
  let size = 1;

  for (let i = 1, n = options.length; i < n; i++) {
    let option = options[i];

    // Если текст элемента содержит наше строку то показываем её, в противоположном слкчае скрываем
    if (option.textContent.toLowerCase().includes(value.toLowerCase())) {
      option.hidden = false;
      size++;
    } else {
      option.hidden = true;
    }
    changeSelectSize(size);
  }
}
.search {
  position: relative;
  display: flex;
  width: 320px;
  height: auto;
}

.search-list-block {
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 1;
}

#search-list {
  width: 100%;
  min-height: 100%;
}

#search-list option {
  height: 100%;
  cursor: pointer;
}

#input-search {
  width: 100%;
  z-index: 2;
}
<div class="search">
  <input type="text" id="input-search">
  <div class="search-list-block">
    <select name="" id="search-list">
      <option selected disabled></option>
      <option value="">Russia</option>
      <option value="">Europe</option>
      <option value="">Asia</option>
      <option value="">Australia</option>
      <option value="">SUA</option>
    </select>
  </div>
</div>

→ Ссылка