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

grouped-options.mddocs/

Grouped Options

Support for hierarchical option structures with group selection capabilities and custom group rendering.

Capabilities

Basic Grouping

Organize options into hierarchical groups with collapsible sections.

/**
 * Basic grouping configuration props
 */
interface BasicGroupingProps {
  /** Property name containing the group's options array */
  groupValues?: string;
  
  /** Property name containing the group's display label */
  groupLabel?: string;
  
  /** Enable selection of entire groups at once (default: false) */
  groupSelect?: boolean;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedEmployees"
    :options="departmentGroups"
    :multiple="true"
    :group-values="'employees'"
    :group-label="'department'"
    :group-select="true"
    label="name"
    track-by="id">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedEmployees: [],
      departmentGroups: [
        {
          department: 'Engineering',
          employees: [
            { id: 1, name: 'John Doe', role: 'Frontend Developer' },
            { id: 2, name: 'Jane Smith', role: 'Backend Developer' }
          ]
        },
        {
          department: 'Design',
          employees: [
            { id: 3, name: 'Alice Johnson', role: 'UX Designer' },
            { id: 4, name: 'Bob Wilson', role: 'Visual Designer' }
          ]
        }
      ]
    }
  }
}
</script>

Group Selection

Enable selection of entire groups with a single click.

/**
 * Group selection configuration props
 */
interface GroupSelectionProps {
  /** Enable group selection functionality */
  groupSelect: true;
  
  /** Label displayed for group selection action */
  selectGroupLabel?: string;
  
  /** Label displayed for group deselection action */
  deselectGroupLabel?: string;
}

Usage Example:

<template>
  <VueMultiselect
    v-model="selectedPermissions"
    :options="permissionGroups"
    :multiple="true"
    :group-values="'permissions'"
    :group-label="'category'"
    :group-select="true"
    select-group-label="Select all permissions in this category"
    deselect-group-label="Remove all permissions in this category"
    label="name"
    track-by="id">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedPermissions: [],
      permissionGroups: [
        {
          category: 'User Management',
          permissions: [
            { id: 'user.create', name: 'Create Users' },
            { id: 'user.edit', name: 'Edit Users' },
            { id: 'user.delete', name: 'Delete Users' }
          ]
        },
        {
          category: 'Content Management',
          permissions: [
            { id: 'content.create', name: 'Create Content' },
            { id: 'content.publish', name: 'Publish Content' }
          ]
        }
      ]
    }
  }
}
</script>

Group State Management

Methods for managing group selection state.

/**
 * Group management methods
 */
interface GroupManagementMethods {
  /** Select all options in a specific group */
  selectGroup(group: any): void;
  
  /** Check if all options in a group are selected */
  wholeGroupSelected(group: any): boolean;
  
  /** Check if all options in a group are disabled */
  wholeGroupDisabled(group: any): boolean;
  
  /** Get CSS classes for group highlighting */
  groupHighlight(index: number, group: any): string;
}

Advanced Group Structure

Handle complex nested group structures with metadata.

<template>
  <VueMultiselect
    v-model="selectedCourses"
    :options="courseGroups"
    :multiple="true"
    :group-values="'courses'"
    :group-label="'subject'"
    :group-select="true"
    label="title"
    track-by="code"
    placeholder="Select courses">

    <template #option="{ option }">
      <div class="course-option">
        <span class="course-title">{{ option.title }}</span>
        <span class="course-credits">{{ option.credits }} credits</span>
        <span class="course-level">Level {{ option.level }}</span>
      </div>
    </template>
    
    <template #tag="{ option, remove }">
      <span class="course-tag">
        {{ option.code }}: {{ option.title }}
        <button @click="remove(option)">×</button>
      </span>
    </template>
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedCourses: [],
      courseGroups: [
        {
          subject: 'Computer Science',
          totalCredits: 24,
          courses: [
            { 
              code: 'CS101', 
              title: 'Introduction to Programming', 
              credits: 4, 
              level: 1,
              prerequisites: []
            },
            { 
              code: 'CS201', 
              title: 'Data Structures', 
              credits: 4, 
              level: 2,
              prerequisites: ['CS101']
            }
          ]
        },
        {
          subject: 'Mathematics',
          totalCredits: 16,
          courses: [
            { 
              code: 'MATH101', 
              title: 'Calculus I', 
              credits: 4, 
              level: 1,
              prerequisites: []
            },
            { 
              code: 'MATH201', 
              title: 'Linear Algebra', 
              credits: 4, 
              level: 2,
              prerequisites: ['MATH101']
            }
          ]
        }
      ]
    }
  }
}
</script>

<style>
.course-option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 0;
}

.course-title {
  font-weight: 500;
}

.course-credits, .course-level {
  font-size: 12px;
  color: #666;
}

.course-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
  background: #e3f2fd;
  border-radius: 3px;
  font-size: 12px;
}
</style>

Group Filtering

Apply search and filtering to grouped options.

<template>
  <VueMultiselect
    v-model="selectedProducts"
    :options="productGroups"
    :multiple="true"
    :searchable="true"
    :group-values="'products'"
    :group-label="'category'"
    :group-select="true"
    label="name"
    track-by="sku"
    placeholder="Search products by category">
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedProducts: [],
      productGroups: [
        {
          category: 'Electronics',
          products: [
            { sku: 'EL001', name: 'Smartphone', price: 699 },
            { sku: 'EL002', name: 'Laptop', price: 1299 },
            { sku: 'EL003', name: 'Headphones', price: 199 }
          ]
        },
        {
          category: 'Books',
          products: [
            { sku: 'BK001', name: 'JavaScript Guide', price: 39 },
            { sku: 'BK002', name: 'Vue.js Cookbook', price: 45 }
          ]
        }
      ]
    }
  }
}
</script>

Custom Group Rendering

Customize the appearance of group headers and options.

<template>
  <VueMultiselect
    v-model="selectedTeamMembers"
    :options="teams"
    :multiple="true"
    :group-values="'members'"
    :group-label="'teamName'"
    :group-select="true"
    label="name"
    track-by="id">

    <template #beforeList>
      <div class="team-stats">
        <strong>{{ selectedTeamMembers.length }}</strong> members selected
      </div>
    </template>

    <template #option="{ option, search }">
      <div class="team-member-option">
        <img :src="option.avatar" :alt="option.name" class="member-avatar">
        <div class="member-info">
          <div class="member-name">{{ option.name }}</div>
          <div class="member-role">{{ option.role }}</div>
          <div class="member-email">{{ option.email }}</div>
        </div>
        <div class="member-status" :class="option.status">
          {{ option.status }}
        </div>
      </div>
    </template>

    <template #tag="{ option, remove }">
      <span class="member-tag">
        <img :src="option.avatar" :alt="option.name" class="tag-avatar">
        {{ option.name }}
        <button @click="remove(option)" class="remove-btn">×</button>
      </span>
    </template>
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedTeamMembers: [],
      teams: [
        {
          teamName: 'Frontend Team',
          teamLead: 'Alice Johnson',
          members: [
            {
              id: 1,
              name: 'Alice Johnson',
              role: 'Team Lead',
              email: 'alice@company.com',
              avatar: '/avatars/alice.jpg',
              status: 'online'
            },
            {
              id: 2,
              name: 'Bob Smith',
              role: 'Senior Developer',
              email: 'bob@company.com',
              avatar: '/avatars/bob.jpg',
              status: 'away'
            }
          ]
        },
        {
          teamName: 'Backend Team',
          teamLead: 'Charlie Brown',
          members: [
            {
              id: 3,
              name: 'Charlie Brown',
              role: 'Team Lead',
              email: 'charlie@company.com',
              avatar: '/avatars/charlie.jpg',
              status: 'online'
            }
          ]
        }
      ]
    }
  }
}
</script>

<style>
.team-stats {
  padding: 8px 12px;
  background: #f5f5f5;
  border-bottom: 1px solid #ddd;
  font-size: 12px;
}

.team-member-option {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  gap: 12px;
}

.member-avatar, .tag-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
}

.tag-avatar {
  width: 20px;
  height: 20px;
}

.member-info {
  flex: 1;
}

.member-name {
  font-weight: 500;
  font-size: 14px;
}

.member-role {
  font-size: 12px;
  color: #666;
}

.member-email {
  font-size: 11px;
  color: #999;
}

.member-status {
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 10px;
  text-transform: uppercase;
}

.member-status.online {
  background: #4caf50;
  color: white;
}

.member-status.away {
  background: #ff9800;
  color: white;
}

.member-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  background: #e3f2fd;
  border-radius: 16px;
  font-size: 12px;
}

.remove-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 16px;
  color: #666;
  padding: 0;
  margin-left: 4px;
}
</style>

Group Events

Events specific to group operations.

/**
 * Group-related events
 */
interface GroupEvents {
  /** Emitted when a group is selected/deselected */
  '@group-select': (group: any, selectedMembers: any[]) => void;
  
  /** Emitted when group selection state changes */
  '@group-change': (group: any, isSelected: boolean) => void;
}

Disabled Groups

Handle disabled state for entire groups or individual options within groups.

<template>
  <VueMultiselect
    v-model="selectedFeatures"
    :options="featureGroups"
    :multiple="true"
    :group-values="'features'"
    :group-label="'plan'"
    :group-select="true"
    label="name"
    track-by="id">

    <template #option="{ option }">
      <div class="feature-option" :class="{ disabled: option.disabled }">
        <span>{{ option.name }}</span>
        <span v-if="option.disabled" class="disabled-reason">
          ({{ option.disabledReason }})
        </span>
      </div>
    </template>
  </VueMultiselect>
</template>

<script>
export default {
  data() {
    return {
      selectedFeatures: [],
      featureGroups: [
        {
          plan: 'Basic Plan',
          features: [
            { id: 1, name: 'Email Support', disabled: false },
            { id: 2, name: 'Basic Analytics', disabled: false }
          ]
        },
        {
          plan: 'Premium Plan', 
          features: [
            { 
              id: 3, 
              name: 'Priority Support', 
              disabled: true,
              disabledReason: 'Upgrade required'
            },
            { 
              id: 4, 
              name: 'Advanced Analytics', 
              disabled: true,
              disabledReason: 'Upgrade required'
            }
          ]
        }
      ]
    }
  }
}
</script>

<style>
.feature-option.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.disabled-reason {
  font-size: 11px;
  color: #999;
  font-style: italic;
}
</style>

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