JSFiddle - React, Tailwind, and code Playground

by Giray

HTML

<script src="https://cdn.jsdelivr.net/gh/giray123/javascript-autocomplete@v1.1/js/autocomplete.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/giray123/javascript-autocomplete@v1.1/css/autocomplete.css">
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Autocomplete for Native Javascript</title>
  </head>

  <body>
    <div id="main">
      <h1>Autocomplete for Native Javascript</h1>
      <p>autocomplete snippet for HTML input fields build with native javascript and no dependencies</p>
      <p>
        This snippet:
        <ul>
          <li>is built with **native javascript**</li>
          <li>is built with <b>native javascript</b></li>
          <li>requires <b>no dependencies</b></li>
          <li>can be used <b>with OR without AJAX</b></li>
          <li>highy <b>customizable</b> yet very <b>simple</b></li>
          <li>user experience is <b>inspired from Google search</b></li>
        </ul>

      </p>

      <h2>Without AJAX (list array)</h2>
      <p>Search for 'apple', 'applepie', 'abacus', 'grape', 'watermelon', 'cherry'</p>
      <input id="search_wihtout_ajax" class="ac-input-default" type="text" placeholder="Search..." autocomplete="off">

      <h2>Without AJAX (list array) and Custom Search Function</h2>
      <p>Search for 'apple', 'applepie', 'abacus', 'grape', 'watermelon', 'cherry'</p>
      <input id="search_wihtout_ajax_custom_search" class="ac-input-default" type="text" placeholder="Search..." autocomplete="off">

      <h2>Built-in AJAX</h2>
      <p>Search for anime names</p>
      <input id="search_auto_ajax" class="ac-input-default" type="text" placeholder="Search..." autocomplete="off">

      <h2>Custom AJAX Handler</h2>
      <input id="search_manual_ajax" class="ac-input-default" type="text" placeholder="Search..." autocomplete="off">
    </div>
  </body>

</html>

CSS

body {
  font-family: sans-serif;
  text-align: center;
  padding-bottom: 400px;
  padding-left: 20px;
  padding-right: 20px;
}

#main {
  width: 100%;
  text-align: left;
}

h1 {
  margin-top: 60px;
}

h2 {
  margin-top: 60px;
}

input.ac-input-default {
  width: 350px;
  transition: all .25s ease-out;
  color: #4a5568;
  padding: 10px 20px 10px 20px;
  line-height: 1.5;
  border-width: 1px;
  border-radius: .5rem;
  border-color: transparent;
  background-color: #edf2f7;
  font-family: sans-serif;
  font-size: 15px;
}

input.ac-input-default:focus {
  outline: none;
  background-color: white;
  border: 1px solid #edf2f7;
}

/* below styles are to grap icons from the cdn instead of the server */
.ac-wrapper .ac-autocomplete-clear-icon {
  background-image: url(https://cdn.jsdelivr.net/gh/giray123/javascript-autocomplete@v1.1/img/clear.svg);
}

.ac-wrapper .ac-autocomplete-loading-icon {
  background-image: url(https://cdn.jsdelivr.net/gh/giray123/javascript-autocomplete@v1.1/img/loading.svg);
}

.ac-wrapper .ac-suggestion-list div.autocomplete-mobile-icon {
  background-image: url(https://cdn.jsdelivr.net/gh/giray123/javascript-autocomplete@v1.1/img/arrow-top-left.svg);
}

JavaScript

var autocomplete = new Autocomplete({
  selector: "#search_wihtout_ajax",
  minChar: 1,
  delay: 100,
  list: ['apple', 'applepie', 'abacus', 'grape', 'watermelon', 'cherry'],
  submitHandler: function(str) {
    console.log("Searched: " + str)
  }
})
var autocomplete = new Autocomplete({
  selector: "#search_wihtout_ajax_custom_search",
  minChar: 1,
  delay: 100,
  list: ['apple', 'applepie', 'abacus', 'grape', 'watermelon', 'cherry'],
  customSearch: function(value, list) {
    var regexp = new RegExp(value.toLowerCase().trim())
    var results = list.filter(v => regexp.test(v)).sort()
    return results
  },
  submitHandler: function(str) {
    console.log("Searched: " + str)
  }
})
var autocomplete = new Autocomplete({
  selector: "#search_auto_ajax",
  minChar: 1,
  maxListHeight: 400,
  ajax: {
    method: "GET",
    url: "https://kitsu.io/api/edge/anime",
    withCredentials: false,
    fields: "?fields[anime]=titles&page[limit]=10&filter[text]",
    responseHandler: function(response) {
      var array = JSON.parse(response).data
        .map(v => v.attributes.titles.en || v.attributes.titles.en_jp)
        .filter(v => v) // remove false/undefined values
      console.log(array, 'array')
      return array
    },
  },
  beforeAjax: function(search) {
    return search.toLowerCase()
  },
  submitHandler: function(str) {
    console.log("Searched: " + str)
  }
})
var autocomplete = new Autocomplete({
  selector: "#search_manual_ajax",
  minChar: 1,
  manualAjax: function(value) {
    return new Promise(function(resolve, reject) {
      var request = new XMLHttpRequest();
      request.open('GET', 'https://kitsu.io/api/edge/anime?fields[anime]=titles&page[limit]=10&filter[text]=' + value, true);
      request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
      request.onreadystatechange = function() {
        if (this.readyState == XMLHttpRequest.DONE && this.status == 200) {
          console.log('succeed');
       ...