JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://unpkg.com/[email protected]/dist/vue-autosuggest.js"></script>
  <script type="text/x-template" id="autocomplete-tpl">
    <div class="autocomplete">
      <label :for="id">{{label}}</label>
      <textarea v-if="textarea" :id="id" :rows="rows" :cols="cols" class="autocomplete-input" :placeholder="placeholder" @focusout="focusout" @focus="focus" @keydown.13="chooseItem" @keydown.tab="chooseItem" @keydown.40="moveDown" @keydown.38="moveUp" v-model="inputValue"
        type="text"></textarea>
      <input v-else :id="id" class="autocomplete-input" :placeholder="placeholder" @focusout="focusout" @focus="focus" @keydown.13="chooseItem" @keydown.tab="chooseItem" @keydown.40="moveDown" @keydown.38="moveUp" v-model="inputValue" type="text">


      <ul :class="{
        'autocomplete-list': true,
        [id+'-list']: true
      }" v-if="searchMatch.length > 0">
        <li :class="{active: selectedIndex === index}" v-for="(result, index) in searchMatch" @click="selectItem(index), chooseItem()" v-html="highlightWord(result)">

        </li>
      </ul>
    </div>
</script>


<div id="app">

 <div class="container">
  <div class="container-row">
   <div class="container-item">
    <h2>VueJs - Autocomplete</h2>
    <p>A small proof of concept of an autocomplete<br />component in VueJS. Use your arrow keys to navigate,<br /> tab to choose first result, <br />enter or mouse to choose selected item.</p>
   </div>


   <div class="container-item">
    <autocomplete label="Standard items:" placeholder="span, div, h1..." />
   </div>

   <div class="container-item">
    <br />
    <br />
    <autocomplete label="Custom items:" :items="['all', 'auto', 'complete', 'items']" placeholder="all, auto..." />
   </div>
		<div class="container-item">
    <br />
    <br />
    <autocomplete label="Textarea" rows="5" placeholder="Your text..." textarea="true" />
   </div>
  </div>
 </div>
</div>

CSS

body {
	height: 100%;
	min-height: 800px;
}
html {
	position: relative;

	width: 100%;
	min-height: 800px;
	height: 100%;
	&:after, &:before {
		position: absolute;

		width: 100%;
		height: 10px;

		content: '';
		z-index: 5;
	}
	&:after {
		top: 0;

		background-color: #4fc08d;
	}
	&:before {
		bottom: 0;

		background-color: #35495e;
	}
}
#app {
	height: 100%;
	margin: 0;
	h2 {
		margin: 0;

		font-weight: 100;
	}
	p {
		margin: 5px 0 30px;

		color: #999;

		font-weight: 100;
		line-height:24px;
		font-size: 15px;
	}
}

.container {
	display: flex;

	height: 100%;

	align-items: center;
	justify-content: center;
	&-row {
		width: auto;
		padding: 25px;

		border-radius: 5px;
		background-color: #f7f7f7;
		box-shadow: 0px 40px 100px -20px rgba(0, 0, 0, 0.1);
	}
	&-item {
		width: 100%;
	}
}


// AUTOCOPMPLETE SCSS
.autocomplete {
	position: relative;
	label {
		display: block;

		margin-bottom: 5px;

		font-size: 14px;
		font-weight: 100;
	}
	&-input {
		padding: 7px 10px;
		width: 93%;
		border: 1px solid #ddd;
		border-radius: 4px;
		outline: none;
		&:focus {
			border-color: #000;
		}
	}
	&-list {
		position: absolute;
		z-index: 2;

		overflow: auto;

		min-width: 250px;
		max-height: 150px;
		margin: 0;
		margin-top: 5px;
		padding: 0;
		
		border: 1px solid #eee;

		list-style: none;

		border-radius: 4px;
		background-color: #fff;
		box-shadow: 0 5px 25px rgba(0, 0, 0, 0.05);
		li {
			margin: 0;
			padding: 8px 15px;

			border-bottom: 1px solid #f5f5f5;
			&:last-child {
				border-bottom: 0;
			}
			&:hover, &.active {
				background-color: #f5f5f5;
			}
		}
	}
}

JavaScript

// TODO: collision detection, autoscroll
// new: tab and highlighting, textareas, follow caret
const standardItems = [
	"input",
	"h1",
	"h2",
	"h3",
	"h4",
	"h5",
	"h6",
	"span",
	"div",
	"textarea",
	"margin",
	"padding",
	"display",
	"background",
	"background-color",
	"background-size",
	"background-repeat",
	"position",
	"top",
	"left",
	"right",
	"bottom",
  "artem derkach",
  "nadya khoroshko"
];
const Autocomplete = Vue.component("autocomplete", {
	template: "#autocomplete-tpl",
	props: ["items", "placeholder", "textarea","label", "rows", "cols"],
	data() {
		return {
			id: 'input-' + parseInt(Math.random() * 1000),
			inputValue: "",
			searchMatch: [],
			selectedIndex: 0,
			clickedChooseItem: false,
			wordIndex: 0
		};
	},
	mounted() {
    const _self = this;
    document.querySelector('#' + this.id)
      .addEventListener('input', function() {
        const caret = getCaretCoordinates(this, this.selectionEnd);

        if (_self.searchMatch.length > 0) {
          const element = document.querySelectorAll('.' + _self.id + '-list');

          if (element[0]) {
            element[0].style.top = caret.top + 40 + 'px';
            element[0].style.left = caret.left + 'px';
          }
        }
      });
  },
	computed: {
		listToSearch() {
			if (typeof this.items !== "undefined" && this.items.length > 0) {
				return this.items;
			} else {
				return standardItems;
			}
		},
		currentWord() {
			return this.inputValue.replace(/(\r\n|\n|\r)/gm, ' ').split(' ')[this.wordIndex];
		},
		inputSplitted() {
			return this.inputValue.replace(/(\r\n|\n|\r)/gm, ' ').split(" ");
		}
	},
	watch: {
		inputValue() {
			this.focus();
			console.log(this.inputSplitted)
			this.selectedIndex = 0;
			this.wordIndex = this.inputSplitted.length - 1;
		}
	},
	methods: {
		highlightWord(word) {
			const regex = new RegExp("(" + this.currentWord + ")", "g");
			return word.replace(regex, '<mark>$1</mark>');
		},
		setWord(word) {
			let currentWords =...