Vue

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-classapplier.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-highlighter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-serializer.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-selectionsaverestore.js"></script>
<div id="app">
		<div class="input__label-wrap">
			<span class="input__label">Cauta</span>
			<div style="user-select: none">
				<span readonly v-on:click="addBooleanTag(b_button)" v-for="b_button in boolean_buttons" class="boolean-buttons">{{b_button.label}}</span>
			</div>
		</div> 
		<div class="input__boolean input__boolean--no-focus">
			<div 
					@keydown.enter.prevent
					@blur="addPlaceholder"
					@keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
					@input="updateBooleanInput($event); clearHtmlElem($event);"
					@paste="pasted"
					v-on:click="clearPlaceholder(); saveCursorLocation($event);"
					class="input__boolean-content"
					ref="divInput"
					contenteditable="true">Cuvinte cheie, cautare booleana..</div>
		</div>
</div>

CSS

.filters__toggler
	{
		cursor: pointer;
		padding: 2px;
		transition: all 0.2s ease-in-out;
		margin-left: 10px;
	}

		.filters__toggler path
		{
			fill: #314964;
		}

	.filters__toggler-collapsed
	{
		transform: rotate(-180deg);
	}

	.input__label
	{
		font-family: $roboto;
		font-size: 14px;
		color: #314964;
		letter-spacing: -0.13px;
		text-align: justify;
	}

	.input__boolean
	{
		width: 100%;
		background: #FFFFFF;
		border: 1px solid #AFB0C3;
		border-radius: 5px;
		padding: 7px 15px 7px;
		font-family: $opensans;
		font-size: 14px;
		color: #082341;
		min-height: 40px;
		box-sizing: border-box;
		margin-top: 15px;
		display: flex;
		flex-direction: row;
		align-items: center;
		line-height: 22px;
		overflow: hidden;
	}

		.input__boolean-content
		{
			width: 100%;
			height: 100%;
			outline: none;
			border: none;
			position: relative;
			padding: 0px;
			word-break: break-word;
		}

		.input__boolean img
		{
			cursor: pointer;
			margin-bottom: -6px;
		}

	.input__boolean--no-focus
	{
		color: #9A9AA6
	}

.input__label-wrap
{
	display: flex;
	justify-content: space-between;
	width: 100%;
	position: relative;
}

	.boolean-buttons
	{
		background-color: #007AFF;
		padding: 3px 15px;
		border-radius: 50px;
		color: #fff;
		font-family: $roboto;
		font-size: 14px;
		font-weight: 300;
		cursor: pointer;
		margin-left: 10px;
	}

		.boolean-button--img
		{
			height: 22px;
			margin-left: 10px;
		}

		.boolean-button--no-margin
		{
			margin: 0;
		}

.popper
{
	background-color: $darkbg;
	font-family: $opensans;
	font-size: 12px;
	line-height: 14px;
	color: #fff;
	padding: 4px 12px;
	border-color: $darkbg;
	box-shadow: 0 5px 12px 0 rgba(49,73,100,0.14);
	border-radius: 8px;
}

.filters__helper
{
	cursor: pointer;
	margin-left: 10px;
	margin-bottom: -3px;
}

.popper[x-placement^="top"] .popper__arrow
{
	border-color: #082341 transparent transparent transparent;
}

Vue

new Vue({
  el: "#app",
		data(){
			return {
				filters_toggled: false,
				fake_input_content: '',
				input_length: 0,
				typed: false,
				boolean_buttons: [{
					type: '1',
					label: 'ȘI',
					tag: 'ȘI',
					img: 'https://i.imgur.com/feHin0S.png'
				}, {
					type: '2',
					label: 'SAU',
					tag: 'SAU',
					img: 'https://i.imgur.com/vWJeJwb.png'
				}, {
					type: '3',
					label: 'NU',
					tag: 'NU',
					img: 'https://i.imgur.com/NNg1spZ.png'
				}],
				saved_sel: 0,
				value: null,
        		options: ['list', 'of', 'options']
			}
		},
		name: 'boolean-input',
		methods: {
			inputLength($event){
				this.input_length = $event.target.innerText.length;
				if(this.input_length == 0)
					this.typed = false;
			},
			addPlaceholder(){
				if(this.input_length == 0 && this.typed == false){
					this.$refs.divInput.innerHTML = 'Cuvinte cheie, cautare booleana..'
				}
			},
			clearPlaceholder(){
				if(this.input_length == 0 && this.typed == false){
					this.$refs.divInput.innerHTML = '';
				}
			},
			updateBooleanInput($event){
				this.typed = true;
				this.inputLength($event);
			},
			saveCursorLocation($event){
      	/*
				if($event.which != 8){
					if(this.saved_sel)
						rangy.removeMarkers(this.saved_sel)
					this.saved_sel = rangy.saveSelection();
				}
				*/
				// if(this.input_length == 0 && this.typed == false){
				// 	var div = this.$refs.divInput;
				// 	var sel = rangy.getSelection();
				// 	sel.collapse(div, 0);
				// }
			},
			insertNode: function(node){
				var selection = rangy.getSelection();
				var range = selection.getRangeAt(0);
				range.insertNode(node);
				range.setStartAfter(node);
				range.setEndAfter(node);
				selection.removeAllRanges();
				selection.addRange(range);
			},
			addBooleanTag($event){
				// return this.$refs.ChatInput.insertEmoji($event.img);
				if (!this.$refs.divInput.contains(document.activeElement))...