Vue-multiselect

The most complete selecting solution for Vue.js

Tag not found. Press semi-colon ; to create a tag from search query.

Getting started


Installation

npm install vue-multiselect --save

Package content

The package consist of of multiple files: Multiselect.vue which includes the template and styling of the default component. This component extends 2 additional mixins: multiselectMixin.js and pointerMixin.js , which contain the logic behind the multiselect. This way you can actually use the multiselect logic with your own template and styling.

Basic usage

multiselect(
  :selected.sync="selected",
  :options="options"
)
import Multiselect from 'vue-multiselect'
export default {
  components: { Multiselect },
  data () {
    return {
      selected: null,
      options: ['list', 'of', 'options']
    }
  }
}

Examples


Single select dropdown (primitive value)

Disabled all highlight label text.

{{ valuePrimitive | json }}
multiselect(
  :options="options",
  :selected.sync="valuePrimitive",
  :multiple="false",
  :searchable="false",
  :close-on-select="false",
  :show-labels="false"
  placeholder="Select one"
  label="name"
)

Single select dropdown (object)

Can't become empty. Showing custom deselect label.

The selected value is referencing the same object as the next example, to show that dynamic preselection works.

{{ value | json }}
multiselect(
  :options="source",
  :selected.sync="value",
  :multiple="false",
  :searchable="false",
  :close-on-select="false",
  :allow-empty="false",
  deselect-label="Can't remove this value"
  key="name"
  label="name"
  placeholder="Select one"
)

The selected value is referencing the same object as the previous example, to show that dynamic preselection works.

{{ value | json }}
multiselect(
  :options="source",
  :selected.sync="value",
  :multiple="false",
  :searchable="true",
  :custom-label="nameWithLang"
  placeholder="Select one",
  label="name",
  key="name"
)

Multiple select with search

Limit visible results to 2.

{{ multiValue | json }}
multiselect(
  :options="source",
  :selected.sync="multiValue",
  :multiple="true",
  :searchable="true",
  :close-on-select="true",
  :clear-on-select="false",
  placeholder="Pick some"
  label="name",
  key="name"
)

Asynchronous dropdown

Changing the search query calls the :on-search-change="" callback function, passing the search query as param. It also sets the loading = true.

To disable loading options have to be updated.

Oops! No elements found. Consider changing the search query.
{{ selectedCountries | json }}
multiselect(
  :options="countries",
  :selected.sync="selectedCountries",
  :multiple="multiple",
  :searchable="searchable",
  placeholder="Type to search",
  :on-search-change="asyncFind | debounce 200",
  :clear-on-select="false",
  label="name"
  key="code"
)
  span(slot="noResult").
    Oops! No elements found. Consider changing the search query.

Tagging

To enable tagging you have to set up 2 props. :taggable="true" and :on-tag="callback" which should add the tag to both Options and Selected arrays.

Oops! No elements found. Consider changing the search query.
{{ taggingSelected | json }}
multiselect(
  :options="taggingOptions",
  :selected="taggingSelected",
  :multiple="multiple",
  :searchable="searchable",
  :on-tag="addTag",
  :on-change="updateSelectedTagging",
  :tagging="true"
  tag-placeholder="Add this as new tag"
  placeholder="Type to search or add tag"
  label="name"
  key="code"
)
  span(slot="noResult").
    Oops! No elements found. Consider changing the search query.
addTag (newTag) {
  const tag = {
    name: newTag,
    // Just for example needs as we use Array of Objects that should have other properties filled.
    // For primitive values you can simply push the tag into options and selected arrays.
    code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
  }
  this.taggingOptions.push(tag)
  this.taggingSelected.push(tag)
},

Vuex support / on-change props

If set triggers the passed callback function after value changes, passing the new value as param.

For Vuex integration simply remove :reset-after="true" prop.

May also act as dispatcher for different actions, like in this example.

multiselect(
  :options="actions",
  :selected="action",
  :multiple="false",
  :searchable="false",
  placeholder="Pick action",
  :reset-after="true",
  :on-change="dispatchAction"
)

Custom configuration

Can't remove the last value and only allow up to 5 selected options.

Hides already selected options.

Shows error when touched, but nothing is selected.

// Template
div(:class="{ 'invalid': isInvalid }")
  label.typo__label Must have at least one value
  multiselect(
    :options="options",
    :selected.sync="exampleValue6",
    :multiple="true",
    :searchable="true",
    :allow-empty="false",
    :hide-selected="true",
    :touched.sync="isTouched",
    :max-height="400",
    :max="5"
    placeholder="Pick at least one"
  )

// Script
computed: {
  isInvalid () {
    return this.isTouched && this.exampleValue6.length === 0
  }
}

// Styles
.invalid {
  .typo__label {
    color: $error-color;
  }
  .multiselect__tags {
    border-color: $error-color !important;
  }
}

Config


Props

// multiselectMixin.js

props: {
  /**
   * Array of available options: Objects, Strings or Integers.
   * If array of objects, visible label will default to option.label.
   * If `labal` prop is passed, label will equal option['label']
   * @type {Array}
   */
  options: {
    type: Array,
    required: true
  },
  /**
   * Equivalent to the `multiple` attribute on a `` input.
   * @default 'Select option'
   * @type {String}
   */
  placeholder: {
    type: String,
    default: 'Select option'
  },
  /**
   * Sets maxHeight style value of the dropdown
   * @default 300
   * @type {Integer}
   */
  maxHeight: {
    type: Number,
    default: 300
  },
  /**
   * Allow to remove all selected values
   * @default true
   * @type {Boolean}
   */
  allowEmpty: {
    type: Boolean,
    default: true
  },
  /**
   * Callback function to call after this.value changes
   * @callback onChange
   * @default false
   * @param {Array||Object||String||Integer} Current this.value
   * @param {Integer} $index of current selection
   * @type {Function}
   */
  onChange: {
    type: Function,
    default: false
  },
  /**
   * Callback function to call after this.search changes
   * @callback onSearchChange
   * @default false
   * @param {String} Pass current search String
   * @type {Function}
   */
  onSearchChange: {
    type: Function,
    default: false
  },
  /**
   * Value that indicates if the dropdown has been used.
   * Useful for validation.
   * @default false
   * @type {Boolean}
   */
  touched: {
    type: Boolean,
    default: false
  },
  /**
   * Reset this.value, this.search, this.selected after this.value changes.
   * Useful if want to create a stateless dropdown, that fires the this.onChange
   * callback function with different params.
   * @default false
   * @type {Boolean}
   */
  resetAfter: {
    type: Boolean,
    default: false
  },
  /**
   * Enable/disable closing after selecting an option
   * @default true
   * @type {Boolean}
   */
  closeOnSelect: {
    type: Boolean,
    default: true
  },
  /**
   * Function to interpolate the custom label
   * @default false
   * @type {Function}
   */
  customLabel: {
    type: Function,
    default: false
  },
  /**
   * Disable / Enable tagging
   * @default false
   * @type {Boolean}
   */
  taggable: {
    type: Boolean,
    default: false
  },
  /**
   * Callback function to run when attemting to add a tag
   * @default suitable for primitive values
   * @param {String} Tag string to build a tag
   * @type {Function}
   */
  onTag: {
    type: Function,
    default: function (tag) {
      this.options.push(tag)
      this.value.push(tag)
    }
  },
  /**
   * String to show when highlighting a potential tag
   * @default 'Press enter to create a tag'
   * @type {String}
  */
  tagPlaceholder: {
    type: String,
    default: 'Press enter to create a tag'
  },
  /**
   * Number of allowed selected options. No limit if false.
   * @default False
   * @type {Number}
  */
  max: {
    type: Number,
    default: false
  }
}

// pointerMixin.js

props: {
  /**
   * Enable/disable highlighting of the pointed value.
   * @type {Boolean}
   * @default true
   */
  showPointer: {
    type: Boolean,
    default: true
  }
}

// Multiselect.vue

props: {
  /**
   * String to show when pointing to an option
   * @default 'Press enter to select'
   * @type {String}
   */
  selectLabel: {
    type: String,
    default: 'Press enter to select'
  },
  /**
   * String to show next to selected option
   * @default 'Selected'
   * @type {String}
  */
  selectedLabel: {
    type: String,
    default: 'Selected'
  },
  /**
   * String to show when pointing to an alredy selected option
   * @default 'Press enter to remove'
   * @type {String}
  */
  deselectLabel: {
    type: String,
    default: 'Press enter to remove'
  },
  /**
   * Decide whether to show pointer labels
   * @default true
   * @type {Boolean}
  */
  showLabels: {
    type: Boolean,
    default: true
  },
  /**
   * Label to look for in option Object
   * @default 'label'
   * @type {String}
   */
  limit: {
    type: Number,
    default: 99999
  },
  /**
   * Function that process the message shown when selected
   * elements pass the defined limit.
   * @default 'and * more'
   * @param {Int} count Number of elements more than limit
   * @type {Function}
   */
  limitText: {
    type: Function,
    default: count => `and ${count} more`
  }
}

Created by Damian Dulisz @DamianDulisz

With love from Monterail