Create Search bar in Vue 3 with Vuetify 3 Vue 3

In this tutorial, we’ll create a search bar using Vuetify.js 3 in Vue.js 3. Before we get started, make sure to install and configure Vuetify 3 in your Vue 3 project.

How to Install Vuetify 3 in Vue 3

Vuetify 3 Vue 3 Search Bar Example

1. Vue 3 Vuetify 3 basic search bar with loading using options api.

Vue
<template>
  <v-card class="mx-auto" color="grey-lighten-3" max-width="400">
    <v-card-text>
      <v-text-field :loading="loading" density="compact" variant="solo" label="Search templates"
        append-inner-icon="mdi-magnify" single-line hide-details @click:append-inner="onClick"></v-text-field>
    </v-card-text>
  </v-card>
</template>
<script>
export default {
  data: () => ({
    loaded: false,
    loading: false,
  }),

  methods: {
    onClick() {
      this.loading = true

      setTimeout(() => {
        this.loading = false
        this.loaded = true
      }, 2000)
    },
  },
}
</script>
vuetify 3 search bar

2. Building a Search Bar with Icon in Vue 3 and Vuetify 3 using Composition API.

Vue
<script setup>
import { ref } from 'vue'

const loaded = ref(false)
const loading = ref(false)

const onClick = async () => {
  loading.value = true
  await new Promise(resolve => setTimeout(resolve, 2000))
  loading.value = false
  loaded.value = true
}
</script>
<template>
  <v-card class="mx-auto" color="grey-lighten-3 mt-5" max-width="400">
    <v-card-text>
      <v-text-field :loading="loading" density="compact" variant="solo" label="Search templates"
        append-inner-icon="mdi-magnify" single-line hide-details @click:append-inner="onClick"></v-text-field>
    </v-card-text>
  </v-card>
</template>

3. Vue 3 and Vuetify 3 Search Bar using JSONPlaceholder Fake API.

Vue
<script setup>
import { ref, watch } from 'vue';

const searchQuery = ref('');
const loading = ref(false);
const users = ref([]);
const filteredUsers = ref([]);

const fetchUsers = async (query) => {
  loading.value = true;
  try {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users?name_like=${encodeURIComponent(query)}`);
    if (!response.ok) throw new Error('Network response was not ok.');
    users.value = await response.json();
    filteredUsers.value = users.value;
  } catch (error) {
    console.error('Error fetching users:', error);
    filteredUsers.value = [];
  } finally {
    loading.value = false;
  }
};

// Debounce search for better performance
let debounceTimeout = null;
const onSearch = () => {
  clearTimeout(debounceTimeout);
  debounceTimeout = setTimeout(() => {
    if (searchQuery.value.trim()) {
      fetchUsers(searchQuery.value.trim());
    } else {
      filteredUsers.value = [];
    }
  }, 300);
};

watch(searchQuery, (newQuery) => {
  if (newQuery === '') {
    filteredUsers.value = [];
  }
});
</script>
<template>
  <v-card class="mx-auto" color="grey-lighten-3" max-width="400">
    <v-card-text>
      <v-text-field v-model="searchQuery" :loading="loading" density="compact" variant="solo" label="Search Users"
        append-inner-icon="mdi-magnify" single-line hide-details @input="onSearch"></v-text-field>
    </v-card-text>
    <v-list dense>
      <v-list-item v-for="user in filteredUsers" :key="user.id">
        <v-list-item-title>{{ user.name }}</v-list-item-title>
        <v-list-item-subtitle>{{ user.email }}</v-list-item-subtitle>
      </v-list-item>
      <v-list-item v-if="filteredUsers.length === 0 && !loading">
        No users found.
      </v-list-item>
    </v-list>
  </v-card>
</template>
vue 3 vuetify 3 search bar

4. Create a Google-like Search Bar Page with Shortcut URLs using Vue 3 and Vuetify 3.

Vue
<template>
  <v-card theme="dark" class="pa-8 d-flex justify-center flex-wrap">
    <v-responsive max-width="550">
      <v-img class="mx-auto mt-12 mb-16" max-height="140" max-width="240"
        src="https://cdn.vuetifyjs.com/docs/images/logos/vuetify-logo-dark-text.svg"></v-img>

      <v-autocomplete :items="items" append-inner-icon="mdi-microphone" auto-select-first class="flex-full-width"
        density="comfortable" item-props menu-icon="" placeholder="Search Google or type a URL"
        prepend-inner-icon="mdi-magnify" rounded theme="light" variant="solo"></v-autocomplete>

      <v-container class="text-center">
        <v-row justify="center" dense>
          <v-col v-for="(shortcut, i) in shortcuts" :key="i" cols="auto">
            <v-card :href="shortcut.href" class="pa-4" flat rel="noopener noreferer" target="_blank" width="112">
              <v-avatar :icon="shortcut.icon" color="white" variant="tonal" class="mb-2"></v-avatar>

              <div class="text-caption text-truncate" v-text="shortcut.title"></div>
            </v-card>
          </v-col>

          <v-col cols="auto">
            <v-dialog v-model="dialog" max-width="500">
              <template v-slot:activator="{ props }">
                <v-card flat width="112" v-bind="props" class="pa-4">

                  <v-avatar icon="mdi-plus" color="white" variant="tonal" class="mb-2"></v-avatar>

                  <div class="text-caption text-truncate">Add shortcut</div>
                </v-card>
              </template>

              <v-card title="Add shortcut" rounded="lg">
                <template v-slot:text>
                  <v-label class="text-caption">Name</v-label>

                  <v-text-field density="compact" variant="solo-filled" flat></v-text-field>

                  <v-label class="text-caption">URL</v-label>

                  <v-text-field density="compact" variant="solo-filled" flat></v-text-field>
                </template>

                <div class="py-4 px-5 text-end">
                  <v-btn border class="text-none me-2" color="blue" text="Cancel" variant="text"
                    @click="dialog = false"></v-btn>

                  <v-btn class="text-none" color="blue" text="Done" variant="flat" @click="dialog = false"></v-btn>
                </div>
              </v-card>
            </v-dialog>
          </v-col>
        </v-row>
      </v-container>
    </v-responsive>
  </v-card>
</template>
<script>
export default {
  data: () => ({
    dialog: false,
    items: [
      {
        prependIcon: 'mdi-clock-outline',
        title: 'recipe with chicken',
      },
      {
        prependIcon: 'mdi-clock-outline',
        title: 'best hiking trails near me',
      },
      {
        prependIcon: 'mdi-clock-outline',
        title: 'how to learn a new language',
      },
      {
        prependIcon: 'mdi-clock-outline',
        title: 'DIY home organization ideas',
      },
      {
        prependIcon: 'mdi-clock-outline',
        title: 'latest fashion trends',
      },
    ],
    shortcuts: [
      {
        icon: 'mdi-github',
        title: 'Master ',
        href: 'https://github.com/vuetifyjs/vuetify',
      },
      {
        icon: 'mdi-github',
        title: 'Dev',
        href: 'https://github.com/vuetifyjs/vuetify/tree/dev',
      },
      {
        icon: 'mdi-github',
        title: 'Stable',
        href: 'https://github.com/vuetifyjs/vuetify/tree/v2-stable',
      },
      {
        icon: 'mdi-github',
        title: 'My Pull Requests',
        href: 'https://github.com/vuetifyjs/vuetify/pulls/johnleider',
      },
    ],
  }),
}
</script>
 vuetify 3 search bar like google
Share link

Leave a Reply

Your email address will not be published. Required fields are marked *