Vue-multiselect

Example fiddle

HTML

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/vue-multiselect.min.css">
<script src="https://unpkg.com/[email protected]/dist/vue-multiselect.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.5.0/vue-resource.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="app">
  <multiselect :options="options" :value="optionsProxy" @input="updateSelected" @search-change="searchQuery" :multiple="true" :searchable="true" :close-on-select="true" placeholder="Search" :custom-label="customLabel" :loading="showLoadingSpinner"></multiselect>

  <ul class="resources-list">
    <template v-for="(resource, index) in selectedResources">
      <li class="resource-item" :data-index="index">
        <div class="resource-info">
          <div class="resource-title" :id="index">
            <span>{{ resource.name }}</span>
            <span class="version">{{resource.version}}</span>
          </div>
          <div class="resource-description">
            <span>{{ resource.description }}</span>
            <span>{{ resource.latest }}</span>
          </div>
          <div class="resource-url">
            <a :href="resource.latest" target="_blank">{{ resource.latest }}</a>
          </div>
        </div>
        <div class="delete-controls" v-on:click.prevent="removeDependency(index)">
          <i class="fa fa-times fa-fw"></i>
        </div>
      </li>
    </template>
  </ul>
</div>

SCSS

* {
  font-family: 'Lato', 'Avenir', sans-serif;
}

.resources-list {
  margin-top: 15px;
  padding: 0;
  list-style: none;
}

.resources-list li {
  display: flex;
  align-items: center;
  min-height: 50px;
  padding: 10px 40px 10px 0;
  border-bottom: 1px solid rgba(51, 51, 51, 0.1);
  position: relative;
}

.resources-list li:last-child {
  border-bottom: none;
}

.resources-list li .resource-title {
  font-size: 1em;
  color: #333;
  max-height: 50px;
  min-height: 50px;
  height: 50px;
}

.resources-list li .version {
  opacity: 0.7;
  margin-left: 5px;
  font-size: 75%;
}

.resources-list li .resource-description,
.resources-list li .resource-url {
  font-size: 0.8em;
  color: #999;
  margin-top: 5px;
}

.resources-list li .resource-url {
  margin-top: 0;
}

.resources-list li .resource-description:empty {
  display: none;
}

.resources-list li .delete-controls {
  position: absolute;
  right: 0;
  width: 40px;
  text-align: center;
  color: #999;
  cursor: pointer;
}

.resources-list li .delete-controls:hover,
.resources-list li .delete-controls:focus {
  color: red;
}

Babel + JSX

new Vue({
	components: {
  	Multiselect: window.VueMultiselect.default
	},
	data: {
  	options: [
    	
    ],
    optionsProxy: [],
    selectedResources: [],
    showLoadingSpinner: false
	},
  methods: {
  	customLabel (option) {
      return `${option.name} - ${option.version}`
    },
    updateSelected(value) {
      value.forEach((resource) => {
      	// Adds selected resources to array
        this.selectedResources.push(resource)
      })
      // Clears selected array
      // This prevents the tags from being displayed
      this.optionsProxy = []
    },
    cdnRequest(value) {
    	this.$http.get(`https://api.cdnjs.com/libraries?search=${value}&fields=version,description`).then((response) => {
        // get body data
        this.options = []
        response.body.results.forEach((object) => {
          this.options.push(object)
        });
				this.showLoadingSpinner = false
      }, (response) => {
        // error callback
      })
    },
    searchQuery(value) {
    	this.showLoadingSpinner = true
    	// GET
      this.cdnRequest(value)
    },
    removeDependency(index) {
      this.selectedResources.splice(index, 1)
    }
  },
  created() {
  	const value = ''
  	this.cdnRequest(value)
  }
}).$mount('#app')