JSFiddle - React, Tailwind, and code Playground

by Geoapify

HTML

<div class="autocomplete-container" id="autocomplete-container"></div>

CSS

body {
  font: 16px;
  background: #f3f5f6;
}

.autocomplete-container {
  /*the container must be positioned relative:*/
  position: relative;
}

.autocomplete-container input {
  width: calc(100% - 43px);
  outline: none;
  
  border: 1px solid rgba(0, 0, 0, 0.2);
  padding: 10px;
  padding-right: 31px;
  font-size: 16px;
}

.autocomplete-items {
  position: absolute;
  border: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.1);
  border-top: none;
  z-index: 99;
  /*position the autocomplete items to be the same width as the container:*/
  top: calc(100% + 2px);
  left: 0;
  right: 0;
}

.autocomplete-items div {
  padding: 10px;
  cursor: pointer;
  background-color: #fff;
}

.autocomplete-items div:hover {
  /*when hovering an item:*/
  background-color: rgba(0, 0, 0, 0.1);
}

.clear-button {
  color: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  
  position: absolute;
  right: 5px;
  top: 0;

  height: 100%;
  display: none;
  align-items: center;
}

.clear-button.visible {
  display: flex;
}


.clear-button:hover {
  color: rgba(0, 0, 0, 0.6);
}

JavaScript

/* 
	The addressAutocomplete takes as parameters:
  - a container element (div)
  - callback to notify about address selection
*/
function addressAutocomplete(containerElement, callback) {
  // create input element
  var inputElement = document.createElement("input");
  inputElement.setAttribute("type", "text");
  inputElement.setAttribute("placeholder", "Enter an address here");
  containerElement.appendChild(inputElement);


  // add input field clear button
  var clearButton = document.createElement("div");
  clearButton.classList.add("clear-button");
  addIcon(clearButton);
  clearButton.addEventListener("click", (e) => {
    e.stopPropagation();
    inputElement.value = '';
    callback(null);
    clearButton.classList.remove("visible");
    closeDropDownList();
  });
  inputElement.parentNode.appendChild(clearButton);

  /* Current autocomplete items data (GeoJSON.Feature) */
  var currentItems;

  /* Active request promise reject function. To be able to cancel the promise when a new request comes */
  var currentPromiseReject;

  /* Execute a function when someone writes in the text field: */
  inputElement.addEventListener("input", function(e) {
    var currentValue = this.value;

    /* Close any already open dropdown list */
    closeDropDownList();

    // Cancel previous request promise
    if (currentPromiseReject) {
      currentPromiseReject({
        canceled: true
      });
    }

    if (!currentValue) {
      clearButton.classList.remove("visible");
      return false;
    }

    // Show clearButton when there is a text
    clearButton.classList.add("visible");

    /* Create a new promise and send geocoding request */
    var promise = new Promise((resolve, reject) => {
      currentPromiseReject = reject;

      var apiKey = "47f523a46b944b47862e39509a7833a9";
      var url = `https://api.geoapify.com/v1/geocode/autocomplete?text=${encodeURIComponent(currentValue)}&limit=5&apiKey=${apiKey}`;

      fetch(url)
        .then(response => {
     ...