Multiple Select Like A Tree – vue3-treeselect

Description:

vue3-treeselect is a multiple select component where you can select nested options in a hierarchical tree structure.

More Features:

  • Live search.
  • Single & Multiple selection.
  • Data lazy loading.
  • Customizable.
  • Keyboard accessibility.

How to use it:

1. Import the vue3-treeselect component and its styles.

import Treeselect from 'vue3-treeselect'
import 'vue3-treeselect/dist/vue3-treeselect.css'

2. Register the component.

export default {
  components: { Treeselect },
}

3. Add a treeselect component to the app and define your options as follows:

<template>
  <div id="app">
    <treeselect v-model="value" :multiple="true" :options="options" />
  </div>
</template>
export default {
  // register the component
  components: { Treeselect },
  data() {
    return {
      value: null,
      options: [ {
        id: '1',
        label: 'Level-1',
        children: [ {
          id: '11',
          label: 'Level-1-1',
        }, {
          id: '12',
          label: 'Level-1-2',
        } ],
      }, {
        id: '2',
        label: 'Level-2',
      }, {
        id: '3',
        label: 'Level-3',
      } ],
    }
  },
}

4. Available props.

/**
 * Whether to allow resetting value even if there are disabled selected nodes.
 */
allowClearingDisabled: {
  type: Boolean,
  default: false,
},

/**
 * When an ancestor node is selected/deselected, whether its disabled descendants should be selected/deselected.
 * You may want to use this in conjunction with `allowClearingDisabled` prop.
 */
allowSelectingDisabledDescendants: {
  type: Boolean,
  default: false,
},

/**
 * Whether the menu should be always open.
 */
alwaysOpen: {
  type: Boolean,
  default: false,
},

/**
 * Append the menu to?
 */
appendToBody: {
  type: Boolean,
  default: false,
},

/**
 * Whether to enable async search mode.
 */
async: {
  type: Boolean,
  default: false,
},

/**
 * Automatically focus the component on mount?
 */
autoFocus: {
  type: Boolean,
  default: false,
},

/**
 * Automatically load root options on mount. When set to `false`, root options will be loaded when the menu is opened.
 */
autoLoadRootOptions: {
  type: Boolean,
  default: true,
},

/**
 * When user deselects a node, automatically deselect its ancestors. Applies to flat mode only.
 */
autoDeselectAncestors: {
  type: Boolean,
  default: false,
},

/**
 * When user deselects a node, automatically deselect its descendants. Applies to flat mode only.
 */
autoDeselectDescendants: {
  type: Boolean,
  default: false,
},

/**
 * When user selects a node, automatically select its ancestors. Applies to flat mode only.
 */
autoSelectAncestors: {
  type: Boolean,
  default: false,
},

/**
 * When user selects a node, automatically select its descendants. Applies to flat mode only.
 */
autoSelectDescendants: {
  type: Boolean,
  default: false,
},

/**
 * Whether pressing backspace key removes the last item if there is no text input.
 */
backspaceRemoves: {
  type: Boolean,
  default: true,
},

/**
 * Function that processes before clearing all input fields.
 * Return `false` to prevent value from being cleared.
 * @type {function(): (boolean|Promise)}
 */
beforeClearAll: {
  type: Function,
  default: constant(true),
},

/**
 * Show branch nodes before leaf nodes?
 */
branchNodesFirst: {
  type: Boolean,
  default: false,
},

/**
 * Should cache results of every search request?
 */
cacheOptions: {
  type: Boolean,
  default: true,
},

/**
 * Show an "×" button that resets value?
 */
clearable: {
  type: Boolean,
  default: true,
},

/**
 * Title for the "×" button when `multiple: true`.
 */
clearAllText: {
  type: String,
  default: 'Clear all',
},

/**
 * Whether to clear the search input after selecting.
 * Use only when `multiple` is `true`.
 * For single-select mode, it **always** clears the input after selecting an option regardless of the prop value.
 */
clearOnSelect: {
  type: Boolean,
  default: false,
},

/**
 * Title for the "×" button.
 */
clearValueText: {
  type: String,
  default: 'Clear value',
},

/**
 * Whether to close the menu after selecting an option?
 * Use only when `multiple` is `true`.
 */
closeOnSelect: {
  type: Boolean,
  default: true,
},

/**
 * How many levels of branch nodes should be automatically expanded when loaded.
 * Set `Infinity` to make all branch nodes expanded by default.
 */
defaultExpandLevel: {
  type: Number,
  default: 0,
},

/**
 * The default set of options to show before the user starts searching. Used for async search mode.
 * When set to `true`, the results for search query as a empty string will be autoloaded.
 * @type {boolean|node[]}
 */
defaultOptions: {
  default: false,
},

/**
 * Whether pressing delete key removes the last item if there is no text input.
 */
deleteRemoves: {
  type: Boolean,
  default: true,
},

/**
 * Delimiter to use to join multiple values for the hidden field value.
 */
delimiter: {
  type: String,
  default: ',',
},

/**
 * Only show the nodes that match the search value directly, excluding its ancestors.
 *
 * @type {Object}
 */
flattenSearchResults: {
  type: Boolean,
  default: false,
},

/**
 * Prevent branch nodes from being selected?
 */
disableBranchNodes: {
  type: Boolean,
  default: false,
},

/**
 * Disable the control?
 */
disabled: {
  type: Boolean,
  default: false,
},

/**
 * Disable the fuzzy matching functionality?
 */
disableFuzzyMatching: {
  type: Boolean,
  default: false,
},

/**
 * Whether to enable flat mode or not. Non-flat mode (default) means:
 *   - Whenever a branch node gets checked, all its children will be checked too
 *   - Whenever a branch node has all children checked, the branch node itself will be checked too
 * Set `true` to disable this mechanism
 */
flat: {
  type: Boolean,
  default: false,
},

/**
 * Will be passed with all events as the last param.
 * Useful for identifying events origin.
*/
instanceId: {
  // Add two trailing "$" to distinguish from explictly specified ids.
  default: () => `${instanceId++}$$`,
  type: [ String, Number ],
},

/**
 * Joins multiple values into a single form field with the `delimiter` (legacy mode).
*/
joinValues: {
  type: Boolean,
  default: false,
},

/**
 * Limit the display of selected options.
 * The rest will be hidden within the limitText string.
 */
limit: {
  type: Number,
  default: Infinity,
},

/**
 * Function that processes the message shown when selected elements pass the defined limit.
 * @type {function(number): string}
 */
limitText: {
  type: Function,
  default: function limitTextDefault(count) { // eslint-disable-line func-name-matching
    return `and ${count} more`
  },
},

/**
 * Text displayed when loading options.
 */
loadingText: {
  type: String,
  default: 'Loading...',
},

/**
 * Used for dynamically loading options.
 * @type {function({action: string, callback: (function((Error|string)=): void), parentNode: node=, instanceId}): void}
 */
loadOptions: {
  type: Function,
},

/**
 * Which node properties to filter on.
 */
matchKeys: {
  type: Array,
  default: constant([ 'label' ]),
},

/**
 * Sets `maxHeight` style value of the menu.
 */
maxHeight: {
  type: Number,
  default: 300,
},

/**
 * Set `true` to allow selecting multiple options (a.k.a., multi-select mode).
 */
multiple: {
  type: Boolean,
  default: false,
},

/**
 * Generates a hidden  tag with this field name for html forms.
 */
name: {
  type: String,
},

/**
 * Text displayed when a branch node has no children.
 */
noChildrenText: {
  type: String,
  default: 'No sub-options.',
},

/**
 * Text displayed when there are no available options.
 */
noOptionsText: {
  type: String,
  default: 'No options available.',
},

/**
 * Text displayed when there are no matching search results.
 */
noResultsText: {
  type: String,
  default: 'No results found...',
},

/**
 * Used for normalizing source data.
 * @type {function(node, instanceId): node}
 */
normalizer: {
  type: Function,
  default: identity,
},

/**
 * By default (`auto`), the menu will open below the control. If there is not
 * enough space, vue-treeselect will automatically flip the menu.
 * You can use one of other four options to force the menu to be always opened
 * to specified direction.
 * Acceptable values:
 *   - `"auto"`
 *   - `"below"`
 *   - `"bottom"`
 *   - `"above"`
 *   - `"top"`
 */
openDirection: {
  type: String,
  default: 'auto',
  validator(value) {
    const acceptableValues = [ 'auto', 'top', 'bottom', 'above', 'below' ]
    return includes(acceptableValues, value)
  },
},

/**
 * Whether to automatically open the menu when the control is clicked.
 */
openOnClick: {
  type: Boolean,
  default: true,
},

/**
 * Whether to automatically open the menu when the control is focused.
 */
openOnFocus: {
  type: Boolean,
  default: false,
},

/**
 * Array of available options.
 * @type {node[]}
 */
options: {
  type: Array,
},

/**
 * Field placeholder, displayed when there's no value.
 */
placeholder: {
  type: String,
  default: 'Select...',
},

/**
 * Applies HTML5 required attribute when needed.
 */
required: {
  type: Boolean,
  default: false,
},

/**
 * Text displayed asking user whether to retry loading children options.
 */
retryText: {
  type: String,
  default: 'Retry?',
},

/**
 * Title for the retry button.
 */
retryTitle: {
  type: String,
  default: 'Click to retry',
},

/**
 * Enable searching feature?
 */
searchable: {
  type: Boolean,
  default: true,
},

/**
 * Search in ancestor nodes too.
 */
searchNested: {
  type: Boolean,
  default: false,
},

/**
 * Text tip to prompt for async search.
 */
searchPromptText: {
  type: String,
  default: 'Type to search...',
},

/**
 * Whether to show a children count next to the label of each branch node.
 */
showCount: {
  type: Boolean,
  default: false,
},

/**
 * Used in conjunction with `showCount` to specify which type of count number should be displayed.
 * Acceptable values:
 *   - "ALL_CHILDREN"
 *   - "ALL_DESCENDANTS"
 *   - "LEAF_CHILDREN"
 *   - "LEAF_DESCENDANTS"
 */
showCountOf: {
  type: String,
  default: ALL_CHILDREN,
  validator(value) {
    const acceptableValues = [ ALL_CHILDREN, ALL_DESCENDANTS, LEAF_CHILDREN, LEAF_DESCENDANTS ]
    return includes(acceptableValues, value)
  },
},

/**
 * Whether to show children count when searching.
 * Fallbacks to the value of `showCount` when not specified.
 * @type {boolean}
 */
showCountOnSearch: null,

/**
 * In which order the selected options should be displayed in trigger & sorted in `value` array.
 * Used for multi-select mode only.
 * Acceptable values:
 *   - "ORDER_SELECTED"
 *   - "LEVEL"
 *   - "INDEX"
 */
sortValueBy: {
  type: String,
  default: ORDER_SELECTED,
  validator(value) {
    const acceptableValues = [ ORDER_SELECTED, LEVEL, INDEX ]
    return includes(acceptableValues, value)
  },
},

/**
 * Tab index of the control.
 */
tabIndex: {
  type: Number,
  default: 0,
},

/**
 * The value of the control.
 * Should be `id` or `node` object for single-select mode, or an array of `id` or `node` object for multi-select mode.
 * Its format depends on the `valueFormat` prop.
 * For most cases, just use `v-model` instead.
 * @type {?Array}
 */
modelValue: null,

/**
 * Which kind of nodes should be included in the `value` array in multi-select mode.
 * Acceptable values:
 *   - "ALL" - Any node that is checked will be included in the `value` array
 *   - "BRANCH_PRIORITY" (default) - If a branch node is checked, all its descendants will be excluded in the `value` array
 *   - "LEAF_PRIORITY" - If a branch node is checked, this node itself and its branch descendants will be excluded from the `value` array but its leaf descendants will be included
 *   - "ALL_WITH_INDETERMINATE" - Any node that is checked will be included in the `value` array, plus indeterminate nodes
 */
valueConsistsOf: {
  type: String,
  default: BRANCH_PRIORITY,
  validator(value) {
    const acceptableValues = [ ALL, BRANCH_PRIORITY, LEAF_PRIORITY, ALL_WITH_INDETERMINATE ]
    return includes(acceptableValues, value)
  },
},

/**
 * Format of `value` prop.
 * Note that, when set to `"object"`, only `id` & `label` properties are required in each `node` object in `value` prop.
 * Acceptable values:
 *   - "id"
 *   - "object"
 */
valueFormat: {
  type: String,
  default: 'id',
},

/**
 * z-index of the menu.
 */
zIndex: {
  type: [ Number, String ],
  default: 999,
},

Preview:

Multiple Select Like A Tree - vue3-treeselect

Download Details:

Author: megafetis

Live Demo: https://megafetis.github.io/vue3-treeselect-demo/

Download Link: https://github.com/megafetis/vue3-treeselect/archive/refs/heads/main.zip

Official Website: https://github.com/megafetis/vue3-treeselect

Install & Download:

# NPM
$ npm i vue3-treeselect

You Might Be Interested In:

Add Comment