Categories
Vuetify

Vuetify — Customize Autocomplete

Spread the love

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Custom Filter on Autocomplete

We can add a custom filter with the v-autocomplete component.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-card class="overflow-hidden" color="purple lighten-1" dark>
          <v-card-text>
            <v-text-field color="white" label="Name"></v-text-field>
            <v-autocomplete
              :items="fruits"
              :filter="customFilter"
              color="white"
              item-text="name"
              label="Fruit"
            ></v-autocomplete>
          </v-card-text>
          <v-divider></v-divider>
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="success" @click="save">Save</v-btn>
          </v-card-actions>
          <v-snackbar
            v-model="hasSaved"
            :timeout="2000"
            absolute
            bottom
            left
          >Your profile has been updated</v-snackbar>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      hasSaved: false,
      model: null,
      fruits: [
        { name: "apple", id: 1 },
        { name: "grape", id: 2 },
        { name: "orange", id: 3 },
      ],
    };
  },

  methods: {
    customFilter(item, queryText, itemText) {
      const text = item.name.toLowerCase();
      const searchText = queryText.toLowerCase();
      return text.indexOf(searchText) > -1;
    },
    save() {
      this.isEditing = !this.isEditing;
      this.hasSaved = true;
    },
  },
};
</script>

We added the v-autocomplete component with the items prop.

The items prop has the items for the autocomplete dropdown.

The filter prop has the filter method that we want to do the filtering with.

Dense Autocomplete

We can add the dense prop to reduce the autocomplete height and decrease the max height.

For instance, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-card class="overflow-hidden" color="purple lighten-1" dark>
          <v-card-text>
            <v-autocomplete
              dense
              :items="fruits"
              :filter="customFilter"
              color="white"
              item-text="name"
              label="Fruit"
            ></v-autocomplete>
          </v-card-text>
          <v-divider></v-divider>
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="success" @click="save">Save</v-btn>
          </v-card-actions>
          <v-snackbar
            v-model="hasSaved"
            :timeout="2000"
            absolute
            bottom
            left
          >Your profile has been updated</v-snackbar>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      hasSaved: false,
      model: null,
      fruits: [
        { name: "apple", id: 1 },
        { name: "grape", id: 2 },
        { name: "orange", id: 3 },
      ],
    };
  },

  methods: {
    customFilter(item, queryText, itemText) {
      const text = item.name.toLowerCase();
      const searchText = queryText.toLowerCase();
      return text.indexOf(searchText) > -1;
    },
    save() {
      this.isEditing = !this.isEditing;
      this.hasSaved = true;
    },
  },
};
</script>

We just add the dense prop to the v-autocomplete to make it shorter.

Slots

We can change the output of the select with slots.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-card color="blue-grey darken-1" dark :loading="isUpdating">
          <v-form>
            <v-container>
              <v-row>
                <v-col cols="12" md="6">
                  <v-text-field
                    v-model="name"
                    :disabled="isUpdating"
                    filled
                    color="blue-grey lighten-2"
                    label="Name"
                  ></v-text-field>
                </v-col>
                <v-col cols="12">
                  <v-autocomplete
                    v-model="friends"
                    :disabled="isUpdating"
                    :items="people"
                    filled
                    chips
                    color="blue-grey lighten-2"
                    label="Select"
                    item-text="name"
                    item-value="name"
                    multiple
                  >
                    <template v-slot:selection="data">
                      <v-chip
                        v-bind="data.attrs"
                        :input-value="data.selected"
                        close
                        @click="data.select"
                        @click:close="remove(data.item)"
                      >
                        <v-avatar left>
                          <v-img :src="data.item.avatar"></v-img>
                        </v-avatar>
                        {{ data.item.name }}
                      </v-chip>
                    </template>
                    <template v-slot:item="data">
                      <template v-if="typeof data.item !== 'object'">
                        <v-list-item-content v-text="data.item"></v-list-item-content>
                      </template>
                      <template v-else>
                        <v-list-item-avatar>
                          <img :src="data.item.avatar" />
                        </v-list-item-avatar>
                        <v-list-item-content>
                          <v-list-item-title v-html="data.item.name"></v-list-item-title>
                          <v-list-item-subtitle v-html="data.item.group"></v-list-item-subtitle>
                        </v-list-item-content>
                      </template>
                    </template>
                  </v-autocomplete>
                </v-col>
              </v-row>
            </v-container>
          </v-form>
          <v-divider></v-divider>
          <v-card-actions>
            <v-btn
              :disabled="autoUpdate"
              :loading="isUpdating"
              color="blue-grey darken-3"
              depressed
              [@click](http://twitter.com/click "Twitter profile for @click")="isUpdating = true"
            >
              <v-icon left>mdi-update</v-icon>Update Now
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data() {
    const src = "https://cdn.vuetifyjs.com/images/lists/1.jpg";
    return {
      autoUpdate: true,
      friends: ["Sandra Adams", "Britta Holt"],
      isUpdating: false,
      name: "",
      people: [
        { name: "Sandra Adams", avatar: src },
        { name: "Mary Smith", avatar: src },
        { name: "James Wong", avatar: src },
      ],
    };
  },

  watch: {
    isUpdating(val) {
      if (val) {
        setTimeout(() => (this.isUpdating = false), 3000);
      }
    },
  },

  methods: {
    remove(item) {
      const index = this.friends.indexOf(item.name);
      if (index >= 0) this.friends.splice(index, 1);
    },
  },
};
</script>

We have the selection slot to populate the name text and the avatar of the person entry.

The v-chip component is a container for both of these items.

This code:

<template v-slot:selection="data">
  <v-chip
  v-bind="data.attrs"
  :input-value="data.selected"
  close
  @click="data.select"
  @click:close="remove(data.item)"
  >
  <v-avatar left>
      <v-img :src="data.item.avatar"></v-img>
  </v-avatar>
  {{ data.item.name }}
  </v-chip>
</template>

has the chip shown when we select an item.

Conclusion

We can add custom filtering and show custom content for autocompletes with Vuetify.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

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