CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-multiselect

Vue 3 compatible multiselect component with advanced selection, search, tagging, and grouping capabilities

Pending
Overview
Eval results
Files

advanced-configuration.mddocs/

Advanced Configuration

Extensive configuration options for behavior control, limits, keyboard handling, and UI customization.

Capabilities

Selection Limits

Control the maximum number of selections and display limits.

/**
 * Selection limit configuration props
 */
interface SelectionLimitProps {
  /** Maximum number of selections allowed (0 = unlimited, default: false) */
  max?: number | boolean;
  
  /** Maximum number of selected options to display (default: 99999) */
  limit?: number;
  
  /** 
   * Function to generate text for excess selections
   * @param count - Number of selections beyond the limit
   * @returns Formatted string for display
   */
  limitText?: (count: number) => string;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedTags"
    :options="availableTags"
    :multiple="true"
    :max="5"
    :limit="3"
    :limit-text="formatLimitText"
    placeholder="Select up to 5 tags">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedTags: [],
      availableTags: ['JavaScript', 'Vue.js', 'React', 'Angular', 'TypeScript', 'Node.js']
    }
  },
  methods: {
    formatLimitText(count) {
      return `and ${count} more tag${count === 1 ? '' : 's'}`;
    }
  }
}
</script>

Behavior Control

Configure component behavior for various user interactions.

/**
 * Behavior control configuration props
 */
interface BehaviorControlProps {
  /** Close dropdown after selecting an option (default: true) */
  closeOnSelect?: boolean;
  
  /** Clear search input after selecting an option (default: true) */
  clearOnSelect?: boolean;
  
  /** Hide already selected options from dropdown (default: false) */
  hideSelected?: boolean;
  
  /** Allow clearing all selections (default: true) */
  allowEmpty?: boolean;
  
  /** Reset component state after selection (stateless mode, default: false) */
  resetAfter?: boolean;
  
  /** Auto-select first option when no value is set (default: false) */
  preselectFirst?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedSkills"
    :options="skills"
    :multiple="true"
    :close-on-select="false"
    :clear-on-select="false"
    :hide-selected="true"
    :allow-empty="true"
    placeholder="Add your skills">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedSkills: [],
      skills: ['JavaScript', 'Python', 'Java', 'C++', 'Go', 'Rust']
    }
  }
}
</script>

Loading States

Display loading indicators during async operations.

/**
 * Loading state configuration props
 */
interface LoadingStateProps {
  /** Show loading spinner (default: false) */
  loading?: boolean;
  
  /** Disable component during loading */
  disabled?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedUser"
    :options="users"
    :loading="isLoading"
    :disabled="isLoading"
    @search-change="searchUsers"
    :internal-search="false"
    placeholder="Search users...">
    
    <template #loading>
      <div class="custom-loading">
        <span>Searching users...</span>
      </div>
    </template>
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedUser: null,
      users: [],
      isLoading: false
    }
  },
  methods: {
    async searchUsers(query) {
      if (!query) return;
      
      this.isLoading = true;
      try {
        const response = await fetch(`/api/users/search?q=${query}`);
        this.users = await response.json();
      } finally {
        this.isLoading = false;
      }
    }
  }
}
</script>

Keyboard Navigation

Configure keyboard behavior and shortcuts.

/**
 * Keyboard navigation configuration props
 */
interface KeyboardNavigationProps {
  /** Array of keyboard keys to block during selection */
  blockKeys?: string[];
  
  /** Prevent automatic focus when component activates (default: false) */
  preventAutofocus?: boolean;
  
  /** HTML tabindex for keyboard navigation order */
  tabindex?: number;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedOption"
    :options="options"
    :block-keys="['Delete', 'Backspace']"
    :prevent-autofocus="true"
    :tabindex="2"
    placeholder="Keyboard navigation disabled">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedOption: null,
      options: ['Option 1', 'Option 2', 'Option 3']
    }
  }
}
</script>

Display Customization

Customize the visual presentation and layout.

/**
 * Display customization configuration props
 */
interface DisplayCustomizationProps {
  /** Maximum height of dropdown in pixels (default: 300) */
  maxHeight?: number;
  
  /** Force dropdown opening direction ('above' | 'below' | '', default: '') */
  openDirection?: string;
  
  /** Show labels for keyboard interactions (default: true) */
  showLabels?: boolean;
  
  /** Show "No options" message when options array is empty (default: true) */
  showNoOptions?: boolean;
  
  /** Show "No results" message when search yields no results (default: true) */
  showNoResults?: boolean;
  
  /** Use Vue 3 Teleport for dropdown positioning (default: false) */
  useTeleport?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedItem"
    :options="largeOptionsList"
    :max-height="200"
    open-direction="above"
    :show-labels="false"
    :use-teleport="true"
    placeholder="Customized dropdown">
    
    <template #noOptions>
      <div class="custom-no-options">
        <i class="icon-search"></i>
        <p>No items available</p>
      </div>
    </template>
    
    <template #noResult="{ search }">
      <div class="custom-no-results">
        <p>No results found for "{{ search }}"</p>
        <button @click="clearSearch">Clear search</button>
      </div>
    </template>
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedItem: null,
      largeOptionsList: Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`)
    }
  },
  methods: {
    clearSearch() {
      // Clear search functionality
      this.$refs.multiselect.updateSearch('');
    }
  }
}
</script>

Performance Optimization

Configure options for optimal performance with large datasets.

/**
 * Performance optimization configuration props
 */
interface PerformanceOptimizationProps {
  /** Maximum number of options to display in dropdown (default: 1000) */
  optionsLimit?: number;
  
  /** Disable internal search for async/custom filtering (default: true) */
  internalSearch?: boolean;
  
  /** Custom sorting function for search results */
  filteringSortFunc?: (a: any, b: any) => number;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedCity"
    :options="filteredCities"
    :options-limit="50"
    :internal-search="false"
    :filtering-sort-func="sortByPopulation"
    @search-change="debounceSearch"
    placeholder="Search cities...">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedCity: null,
      allCities: [], // Large dataset of cities
      filteredCities: [],
      searchTimeout: null
    }
  },
  methods: {
    debounceSearch(query) {
      clearTimeout(this.searchTimeout);
      this.searchTimeout = setTimeout(() => {
        this.performSearch(query);
      }, 300);
    },
    
    performSearch(query) {
      if (!query) {
        this.filteredCities = this.allCities.slice(0, 50);
        return;
      }
      
      this.filteredCities = this.allCities
        .filter(city => city.name.toLowerCase().includes(query.toLowerCase()))
        .slice(0, 50);
    },
    
    sortByPopulation(a, b) {
      return b.population - a.population;
    }
  }
}
</script>

Navigation and Pointer

Control dropdown navigation highlighting and option height calculations.

/**
 * Navigation and pointer configuration props
 */
interface NavigationPointerProps {
  /** Enable/disable highlighting of the pointed value (default: true) */
  showPointer?: boolean;
  
  /** Height of each option in pixels for scroll calculations (default: 40) */
  optionHeight?: number;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedOption"
    :options="longOptionsList"
    :show-pointer="true"
    :option-height="35"
    placeholder="Navigate with arrow keys">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedOption: null,
      longOptionsList: Array.from({ length: 1000 }, (_, i) => `Option ${i + 1}`)
    }
  }
}
</script>

Component State Reset

Configure automatic state reset for stateless usage patterns.

/**
 * State reset configuration props
 */
interface StateResetProps {
  /** Reset internal state after each selection (default: false) */
  resetAfter?: boolean;
  
  /** Preserve search value across selections (default: false) */
  preserveSearch?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="currentSelection"
    :options="dynamicOptions"
    :reset-after="true"
    :preserve-search="false"
    @select="handleSelection"
    placeholder="Stateless selector">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      currentSelection: null,
      dynamicOptions: [],
      selectionHistory: []
    }
  },
  methods: {
    handleSelection(selected) {
      // Process selection
      this.selectionHistory.push(selected);
      
      // Update options based on selection
      this.updateOptionsForNextSelection(selected);
    },
    
    updateOptionsForNextSelection(lastSelected) {
      // Logic to update options based on previous selection
      this.dynamicOptions = this.getNextOptions(lastSelected);
    }
  }
}
</script>

Accessibility Configuration

Configure accessibility features and ARIA attributes.

/**
 * Accessibility configuration props
 */
interface AccessibilityProps {
  /** HTML required attribute when no value selected */
  required?: boolean;
  
  /** Tab index for keyboard navigation */
  tabindex?: number;
  
  /** Component name for form submission and ARIA labels */
  name?: string;
  
  /** Enable spellcheck on search input */
  spellcheck?: boolean;
  
  /** Show pointer/selection labels for screen readers */
  showLabels?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedAccessibleOption"
    :options="accessibleOptions"
    :required="true"
    :tabindex="1"
    name="accessible-select"
    :spellcheck="true"
    :show-labels="true"
    select-label="Press enter to select this option"
    deselect-label="Press enter to remove this option"
    placeholder="Accessible multiselect">
  </VueMultiselect>
</template>

Advanced Event Handling

Configure component identification for complex event handling scenarios.

/**
 * Event handling configuration props
 */
interface EventHandlingProps {
  /** 
   * Unique identifier passed with all events for component identification
   * Useful when multiple multiselect components exist
   */
  id?: string | number | null;
}

/**
 * All events include the component ID as second parameter
 */
interface EventHandlingEvents {
  '@update:modelValue': (value: any, id: string | number) => void;
  '@select': (option: any, id: string | number) => void;
  '@remove': (option: any, id: string | number) => void;
  '@search-change': (query: string, id: string | number) => void;
  '@open': (id: string | number) => void;
  '@close': (value: any, id: string | number) => void;
  '@tag': (query: string, id: string | number) => void;
}

Usage Example:

<template>
  <div>
    <VueMultiselect
      v-model="userSelection"
      :options="users"
      id="user-selector"
      @select="handleSelect"
      @remove="handleRemove">
    </VueMultiselect>
    
    <VueMultiselect
      v-model="roleSelection"
      :options="roles"
      id="role-selector"
      @select="handleSelect"
      @remove="handleRemove">
    </VueMultiselect>
  </div>
</template>

<script>
export default {
  methods: {
    handleSelect(option, componentId) {
      console.log(`Selected ${option.name} from ${componentId}`);
      
      if (componentId === 'user-selector') {
        this.handleUserSelection(option);
      } else if (componentId === 'role-selector') {
        this.handleRoleSelection(option);
      }
    },
    
    handleRemove(option, componentId) {
      console.log(`Removed ${option.name} from ${componentId}`);
    }
  }
}
</script>

Install with Tessl CLI

npx tessl i tessl/npm-vue-multiselect

docs

advanced-configuration.md

basic-selection.md

custom-rendering.md

grouped-options.md

index.md

search-filtering.md

tagging-mode.md

tile.json