JSFiddle - React, Tailwind, and code Playground

by neonDog

HTML

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">

<div class="col-6">

  <h4>Autocomplete</h4>

  <div class="neon-autocomplete"></div>

  <h4>Select</h4>

  <div class="neon-autocomplete"></div>

  <h4>Tags</h4>
  
  <div class="neon-autocomplete"></div>

</div>

SCSS

.neon-autocomplete {
  position: relative;
}
.neon-dropdown-item.hidden {
  display:none;
}

.neon-dropdown-menu {
  &.hidden {
    display:none;
  }
}
.neon-autocomplete-main + .neon-dropdown-menu {
  display: block;
  position: absolute;
  opacity: 0;
  transform: translateY(-15px);
  height: 1px;
  min-width: 100%;
  transition: transform .2s ease, opacity .1s ease-out;
  overflow-y: auto;
  max-height: 300px;
}

.neon-autocomplete-main:focus + .neon-dropdown-menu,
.neon-dropdown-menu:focus-within,
.neon-dropdown-menu.show {
  opacity: 1;
  transform: translateY(0px);
  height: auto;
  z-index: 1;
}

JavaScript

const textHighlight = function(string, search, addClass='text-highlight') {
  if (!search) return string;
  if (typeof string !== 'string') return string;
  let returnString = string;
  const regex = new RegExp("(" + search + ")(?![^<]*>|[^<>]*</)", "i"); // explanation: http://stackoverflow.com/a/18622606/1147859

  const match = string.match(regex)
  if (match) {
    // Get to highlighting
    var matchStartPosition = string.match(regex).index;
    var matchEndPosition = matchStartPosition + string.match(regex)[0].toString().length;
    var originalTextFoundByRegex = string.substring(matchStartPosition, matchEndPosition);
    returnString = returnString.replace(regex, `<mark class="${ addClass }">${originalTextFoundByRegex}</mark>`);
  }

  return returnString;
};

class NeonDropdown {

  constructor(element, settings = {}) {

    const defaults = {
      //addEventListeners:false
      class:'dropdown-menu',
      itemClass:'dropdown-item',
      activeClass:'active',
      loop: true,
      onSelect: function(element){}
    };

    this.options = Object.assign({}, defaults, settings);
    this.element = element;
    this.element.classList.add('neon-dropdown-menu');
    this.element.setAttribute('tabindex', '0');
    if (this.options.class) {
    	this.element.classList.add(this.options.class);
    }
    
    this.activeOption = null;
    this._click = this._click.bind(this);
    this._keydown = this._keydown.bind(this);
    this._mouseover = this._mouseover.bind(this);
    this.eventListenersActive = false;
    this.eventListeners(true);
  }
  
  showHide(show = true) {
    this.element.classList.toggle('hidden', !show);
  }

  scroll(down = true) {
		
    const selector = 'neon-dropdown-item';
		let newH = this.activeOption ? getNextPrevSibling(this.activeOption, '.' + selector, down) : this.element.getElementsByClassName(selector)[0];
    
    if (!newH && this.options.loop) { // Logic for looping back to top or going to the bottom if enabled
      const...