John Au-Yeung I'm a web developer interested in JavaScript stuff.

Exploring Vue-Multiselect

6 min read 1756

Exploring Vue-Multiselect

Creating dropdown menus is always tough, especially if we need to apply custom styling to it — the select element is very limited in what it can do. Therefore, if we’re using Vue to build our apps, we can use some components to help make our lives easier.

In this article, we’ll look at how the Vue-Multiselect library can help improve our dropdown menus.

Getting started

To get started, we can install Vue-Multiselect by running:

npm install vue-multiselect --save

We can also add the library via script tags and add the CSS that’s associated with the package:

<script src="https://unpkg.com/vue-multiselect@2.1.0"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-multiselect@2.1.0/dist/vue-multiselect.min.css">

Then, in our component, we can write:

<template>
  <div>
    <multiselect v-model="value" :options="options"></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: null,
      options: ["foo", "baz", "baz"]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

The Multiselect component is registered to the component. We have the multiselect component with v-model to bind to the value state. The options prop is set to options, which has an array of strings.

Because of this, the value displayed to the user will be the same as the selected value; we can see that from the <p> element below the dropdown. Also note that we added the styles from the package with the style tag.

Single select with objects

If we want to display items to the user and keep the values different from what’s displayed, then we need to have an array of objects for options.

For instance, we write:

<template>
  <div>
    <multiselect track-by="name" label="name" v-model="value" :options="options"></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: null,
      options: [
        { name: "Orange", value: "orange" },
        { name: "Apple", value: "apple" },
        { name: "Grape", value: "grape" }
      ]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

We display the values in the name properties because we set label to name. Now when we select a value, we select the whole object, and value is set to the object selected when we pick an item.

We made a custom demo for .
No really. Click here to check it out.

Add search

Search is available by default since the searchable prop is set to true by default. We can display custom text for the dropdown entries with the custom-label prop, which we set to a function.

For instance, we can write:

<template>
  <div>
    <multiselect
      track-by="name"
      label="name"
      :custom-label="nameFormatter"
      v-model="value"
      :options="options"
    ></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: null,
      options: [
        { name: "Orange", color: "orange", value: "orange" },
        { name: "Apple", color: "red", value: "apple" },
        { name: "Grape", color: "purple", value: "grape" }
      ]
    };
  },
  methods: {
    nameFormatter({ name, color }) {
      return `${name} - ${color}`;
    }
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

Now we get what’s returned in the nameFormatter displayed for each entry.

Multiple select

Vue-Multiselect also supports multiple selections. For example, we can write:

<template>
  <div>
    <multiselect track-by="name" label="name" v-model="value" :options="options" multiple></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: null,
      options: [
        { name: "Orange", value: "orange" },
        { name: "Apple", value: "apple" },
        { name: "Grape", value: "grape" }
      ]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

We added multiple to multiselect to enable multiple selection. We can add text to display when something is selected by filling the selection slot, like so:

<template>
  <div>
    <multiselect track-by="name" label="name" v-model="value" :options="options" multiple>
      <template slot="selection" slot-scope="{ values, search, isOpen }">
        <span v-if="values.length">{{ values.length }} options selected</span>
      </template>
    </multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: null,
      options: [
        { name: "Orange", value: "orange" },
        { name: "Apple", value: "apple" },
        { name: "Grape", value: "grape" }
      ]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

The selection slot has the values property with the selected values. isOpen indicates whether the menu is open or not, and search has the search term.

Allow tag input

We can also let users add tags with Vue-Multiselect.

To let users add tags, we can write the following:

<template>
  <div>
    <multiselect v-model="values" taggable @tag="addTag" :options="options" multiple></multiselect>
    <p>{{values}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      values: [],
      options: ["orange", "apple", "grape"]
    };
  },
  methods: {
    addTag(newTag) {
      this.options.push(newTag);
      this.values.push(newTag);
    }
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

We add the taggable prop to let users enter their own tags, and we listen to the tag event emitted by multiselect by running the addTag method. It takes the newTag parameter, which has the tag name.

In the method, we add the this.values and this.options so that the new tag can be added to the list of options and to the list of the selected values.

Custom option template

One great feature of Vue-Multiselect is that the dropdown items can contain text and images.

We can write:

<template>
  <div>
    <multiselect v-model="values" :options="options">
      <template slot="singleLabel" slot-scope="props">
        <img class="option-image" :src="props.option.img">
        <div>
          <span>{{ props.option.title }}</span>
        </div>
      </template>
      <template slot="option" slot-scope="props">
        <img class="option-image" :src="props.option.img">
        <div>
          <span>{{ props.option.title }}</span>
        </div>
      </template>
    </multiselect>
    <p>{{values}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      values: [],
      options: [
        {
          title: "orange",
          img:
            "https://secure.webtoolhub.com/static/resources/icons/set114/5cfa0390.png"
        },
        {
          title: "apple",
          img:
            "https://images.squarespace-cdn.com/content/v1/56ed6e3b1bbee05366b9f7a5/1464743651591-TJG1VO66UK1GI9LJ5WDO/ke17ZwdGBToddI8pDm48kHhlTY0to_qtyxq77jLiHTtZw-zPPgdn4jUwVcJE1ZvWhcwhEtWJXoshNdA9f1qD7T-j82ScS_xjTqFYGqFrT72qZ_E0ELtHpOZiWcSG1QwIMeEVreGuQ8F95X5MZTW1Jw/lodi-apple.png?format=300w"
        },
        {
          title: "grape",
          img:
            "https://icons.iconarchive.com/icons/martin-berube/food/256/grapes-icon.png"
        }
      ]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

<style>
.option-image {
  width: 100px;
}
</style>

We populate the singleLabel slot with an image and text for the dropdown entry. The option slot is populated the same way for populating the dropdown options.

Option groups

Options can be grouped instead of placing options all at the top level, like so:

<template>
  <div>
    <multiselect
      group-values="items"
      group-label="type"
      group-select
      v-model="value"
      :options="options"
      label="name"
    ></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";

export default {
  components: { Multiselect },
  data() {
    return {
      value: undefined,
      options: [
        {
          type: "fruit",
          items: [{ name: "apple" }, { name: "orange" }]
        },
        {
          type: "drink",
          items: [{ name: "beer" }, { name: "wine" }]
        }
      ]
    };
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

options is an array of objects with a property for the group label, which, in our example, is type. items has the items in the dropdown groups.

group-values is set to the items property to use them as group items, and  group-label is set to type to display as group headings. label is set to the name property to display that to the user.

Vuex integration

Vue-Multiselect integrates with Vuex to let us store the choices in a Vuex store instead of the component.

For instance, we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    value: "apple",
    options: ["apple", "orange", "grape"]
  },
  mutations: {
    updateValue(state, value) {
      state.value = value;
    }
  },
  actions: {
    updateValueAction({ commit }, value) {
      commit("updateValue", value);
    }
  }
});

Vue.config.productionTip = false;

new Vue({
  store,
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div>
    <multiselect :value="value" @input="updateValueAction" :options="options"></multiselect>
    <p>{{value}}</p>
  </div>
</template>

<script>
import Multiselect from "vue-multiselect";
import Vuex from "vuex";

const { mapActions, mapState } = Vuex;

export default {
  components: {
    Multiselect
  },
  computed: {
    ...mapState(["value", "options"])
  },
  methods: {
    ...mapActions(["updateValueAction"])
  }
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

In main.js, we used the Vuex.Store constructor to create the store with the value and options states. We have a mutation to update the value, which is used by the updateValueAction to update the value state, then we put the store in the object we passed into the Vue constructor.

In App.vue, instead of binding our dropdown’s selected value with v-model, we map the states with mapState to get the states from the store. And we have mapActions to map the updateValueAction from the store to update the value.

We listen to the input event to get the item and call updateValueAction to update the value state with in the Vuex store via the mutation. Also, we set the value of the value prop from the store. The input event and value prop replace v-model.

The options are also set from the options state from the Vuex store via the mapState method.

Conclusion

Vue-Multiselect is a very flexible dropdown component to let us create dropdowns that can have pictures and dropdown items with formatting.

We can also group dropdown options and enable multiple selections and tagging. It has integration with Vuex allows us to get and set options and values from the store.

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

John Au-Yeung I'm a web developer interested in JavaScript stuff.

Leave a Reply