How to use type-a-head in vue3

With vue-select package

You can do it like this in the vue-select package

  <template>
      <vSelect v-model="selectedValue"  :noDrop="searchInput === ''" :filterable="false" :options="options" class="bg-white" @search="searching" />
  </template>

  <script setup>
  import vSelect from 'vue-select'
  import {ref} from "vue";
  import axios from 'axios';
  import { debounce } from "lodash";
  import "vue-select/dist/vue-select.css";

  const options = ref([]);
  const searchInput = ref('');
  const selectedValue = ref(null);

  const searching = debounce( async function (search, loading) {
      loading(true);
      searchInput.value = search;
      axios.post('/dashboard/users/search', {key: search.trim()})
          .then(response => {
              options.value = response.data;
          })
          .catch(error => {
              console.error(error);
          })
          .finally(() => {
              loading(false);
          });
  }, 200);
  </script>

  <style scoped>
  :deep(.vs__search::placeholder ){
      color: rgba(0, 0, 0, 0.4);
  }
  </style>

I used

:noDrop="searchInput === ''"

because otherwise, you would get a "Nothing found" message when you first enter the select box (and your ajax call is not returning.

I also had to disable filtering like this:

:filterable="false"

Because otherwise, it would search in local search results. Since I can't display all search results at once (have to limit them on the backend, becaue ther are soo many results), it would happen, then when you enter slowly a name, it could be that you get a "not found" inbetween.

The debounce is used to not trigger an ajax request on every keystore. The scoped style is used because I am using Tailwind and it was breaking the placeholder layout.

With Vue Multiselect

This is same thing used in VueMultiselect. Exact same resons as above for internal-search, debounce, and showNoOptions..

<template>
        <VueMultiselect
            v-model="selected"
            :options="options"
            :multiple="false"
            :searchable="true"
            @search-change="asyncFind"
            label="label"
            track-by="value"
            :loading="loading"
            :internal-search="false"
            :showNoOptions="selected !== null || loading"
        >
            <template #noResult>
                 <span v-if="!loading">
                    No user found
                </span>
                <span v-else>
                  Loading...
                </span>
            </template>
        </VueMultiselect>
</template>

<script setup>
import VueMultiselect from 'vue-multiselect'
import axios from "axios";
import {ref} from "vue";
import { debounce } from "lodash";

const selected = ref(null);
const options = ref([]);
const loading = ref(false);
const asyncFind = debounce( async function (query) {
    loading.value = true;
    axios.post('/dashboard/users/search', {key: query.trim()})
        .then(response => {
            options.value = response.data;
        })
        .catch(error => {
            console.error(error);
        })
        .finally(() => {
            loading.value = false;
        });
}, 500);
</script>

<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style scoped>
 :deep(input[type='text']:focus) {
    outline: none;
    --tw-ring-offset-width: 0;
    --tw-ring-color: transparent;
    --tw-ring-offset-color: transparent;
    --tw-ring-shadow: none;
    --tw-ring-offset-shadow: none;
    box-shadow: none;
    border-color: initial;
}
</style>
``