JSFiddle - React, Tailwind, and code Playground

by dumptyd

HTML

<div id="target"></div>

SCSS

.kb-select {
  border: 1px solid #888;
  padding: 5px;
  display: inline-block;
  
  .kb-select-popup-wrapper:not(.visible) {
    display: none;
  }
  
  .kb-select-popup-wrapper {
    .kb-select-search {
      border: 1px solid #ccc;
      padding: 5px;
    }
  }
}

JavaScript

const $$ = document.querySelectorAll.bind(document);
const $ = document.querySelector.bind(document);

const el = $('#target');
const data = ['Apple', 'Banana', 'Cat', 'Bank', 'Elephant', 'Frog', 'Giraffe'];

class KbSelect {
	constructor(el, data, options={}) {
  	if (!el || !data || !data.length) {
    	throw new Error('Invalid parameters.');
    }
    this.el = el;

		this.itemClass = options.itemClass || 'kb-select-item';
    this.searchClass = options.searchClass || 'kb-select-search';

		this.elements = this._generateItems(data);
    this.filteredElements = this.elements.slice();
    this._createUI();
  }
  _generateItems(data) {
  	return data.map(d => this._createItem(d));
  }
  _createItem(label) {
  	const div = document.createElement('DIV');
    div.classList.add(this.itemClass);
    div.innerText = label;
    return div;
  }
  _createSearch() {
  	const input = document.createElement('INPUT');
    input.classList.add(this.searchClass);
    const valMap = { type: 'text', placeholder: 'Search' };
    Object.keys(valMap).forEach(k => {
    	input[k] = valMap[k];
    });
    input.addEventListener('input', this._changeHandler.bind(this));
    return input;
  }
  _changeHandler(e) {
  	const val = e.target.value.toLowerCase();
    this.filteredElements = this.elements.filter(e => e.innerText.toLowerCase().includes(val));
    this._triggerOptionsChange();
  }
	_createUI() {
  	const popupWrapper = document.createElement('DIV');
    popupWrapper.classList.add('kb-select-popup-wrapper');
    this.popupWrapper = popupWrapper;
    
    const itemWrapper = document.createElement('DIV');
    itemWrapper.classList.add('kb-select-item-wrapper');
    this.itemWrapper = itemWrapper;
    
    const valEl = document.createElement('DIV');
    valEl.classList.add('kb-select-display');
    valEl.innerText = 'Select a value';
    valEl.addEventListener('click', () => {
    	this.popupWrapper.classList.toggle('visible');
    });
    
    this.el.classList.add('kb-select');
...