JSFiddle - React, Tailwind, and code Playground

by leopoldthecuber

HTML

<div>
  <form>
    <input type="text">
  </form>
</div>

CSS

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

div {
  padding: 50px;
}

ul {
  list-style: none;
  position: absolute;
  border: solid 1px black;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

JavaScript

class Autocomplete {
  constructor(targetEl, props) {
    this.results = [];
    this.targetEl = targetEl;
    this.el = document.createElement('ul');
    this.el.style.display = 'none';
    document.body.appendChild(this.el);
    
    this.targetEl.addEventListener('input', e => {
      const { value } = e.target;
      this.el.innerHTML = '';
      if (value) {
        this.search(value);
      }
    });
    
    this.hide = this.hide.bind(this);
    this.onClick = this.onClick.bind(this);
  }
  
  search(value) {
    this.results = [
      `result 1 for ${value}`,
      `result 2 for ${value}`,
      `result 3 for ${value}`
    ];
    this.show();
  }
  
  show() {
    const fragment = document.createDocumentFragment();
    this.results.forEach((item) => {
      const li = document.createElement('li');
      li.innerText = item;
      fragment.appendChild(li);
    });
    this.el.appendChild(fragment);
    const { bottom, left, width } = this.targetEl.getBoundingClientRect();
    this.el.style.display = 'block';
    this.el.style.top = `${bottom + 5}px`;
    this.el.style.left = `${left}px`;
    this.el.style.width = `${width}px`;
    this.el.addEventListener('click', this.onClick);
    
    document.body.addEventListener('click', this.hide);
  }
  
  hide() {
    document.body.removeEventListener('click', this.hide);
    this.el.removeEventListener('click', this.onClick);
    this.el.style.display = 'none';
    this.el.innerHTML = '';
  }

  onClick(e) {
    this.targetEl.value = e.target.innerText;
    e.stopPropagation();
  }
}

const autocomplete = new Autocomplete(document.querySelector('input'));