0
# Grouped Options
1
2
Support for hierarchical option structures with group selection capabilities and custom group rendering.
3
4
## Capabilities
5
6
### Basic Grouping
7
8
Organize options into hierarchical groups with collapsible sections.
9
10
```typescript { .api }
11
/**
12
* Basic grouping configuration props
13
*/
14
interface BasicGroupingProps {
15
/** Property name containing the group's options array */
16
groupValues?: string;
17
18
/** Property name containing the group's display label */
19
groupLabel?: string;
20
21
/** Enable selection of entire groups at once (default: false) */
22
groupSelect?: boolean;
23
}
24
```
25
26
**Usage Example:**
27
28
```vue
29
<template>
30
<VueMultiselect
31
v-model="selectedEmployees"
32
:options="departmentGroups"
33
:multiple="true"
34
:group-values="'employees'"
35
:group-label="'department'"
36
:group-select="true"
37
label="name"
38
track-by="id">
39
</VueMultiselect>
40
</template>
41
42
<script>
43
export default {
44
data() {
45
return {
46
selectedEmployees: [],
47
departmentGroups: [
48
{
49
department: 'Engineering',
50
employees: [
51
{ id: 1, name: 'John Doe', role: 'Frontend Developer' },
52
{ id: 2, name: 'Jane Smith', role: 'Backend Developer' }
53
]
54
},
55
{
56
department: 'Design',
57
employees: [
58
{ id: 3, name: 'Alice Johnson', role: 'UX Designer' },
59
{ id: 4, name: 'Bob Wilson', role: 'Visual Designer' }
60
]
61
}
62
]
63
}
64
}
65
}
66
</script>
67
```
68
69
### Group Selection
70
71
Enable selection of entire groups with a single click.
72
73
```typescript { .api }
74
/**
75
* Group selection configuration props
76
*/
77
interface GroupSelectionProps {
78
/** Enable group selection functionality */
79
groupSelect: true;
80
81
/** Label displayed for group selection action */
82
selectGroupLabel?: string;
83
84
/** Label displayed for group deselection action */
85
deselectGroupLabel?: string;
86
}
87
```
88
89
**Usage Example:**
90
91
```vue
92
<template>
93
<VueMultiselect
94
v-model="selectedPermissions"
95
:options="permissionGroups"
96
:multiple="true"
97
:group-values="'permissions'"
98
:group-label="'category'"
99
:group-select="true"
100
select-group-label="Select all permissions in this category"
101
deselect-group-label="Remove all permissions in this category"
102
label="name"
103
track-by="id">
104
</VueMultiselect>
105
</template>
106
107
<script>
108
export default {
109
data() {
110
return {
111
selectedPermissions: [],
112
permissionGroups: [
113
{
114
category: 'User Management',
115
permissions: [
116
{ id: 'user.create', name: 'Create Users' },
117
{ id: 'user.edit', name: 'Edit Users' },
118
{ id: 'user.delete', name: 'Delete Users' }
119
]
120
},
121
{
122
category: 'Content Management',
123
permissions: [
124
{ id: 'content.create', name: 'Create Content' },
125
{ id: 'content.publish', name: 'Publish Content' }
126
]
127
}
128
]
129
}
130
}
131
}
132
</script>
133
```
134
135
### Group State Management
136
137
Methods for managing group selection state.
138
139
```typescript { .api }
140
/**
141
* Group management methods
142
*/
143
interface GroupManagementMethods {
144
/** Select all options in a specific group */
145
selectGroup(group: any): void;
146
147
/** Check if all options in a group are selected */
148
wholeGroupSelected(group: any): boolean;
149
150
/** Check if all options in a group are disabled */
151
wholeGroupDisabled(group: any): boolean;
152
153
/** Get CSS classes for group highlighting */
154
groupHighlight(index: number, group: any): string;
155
}
156
```
157
158
### Advanced Group Structure
159
160
Handle complex nested group structures with metadata.
161
162
```vue
163
<template>
164
<VueMultiselect
165
v-model="selectedCourses"
166
:options="courseGroups"
167
:multiple="true"
168
:group-values="'courses'"
169
:group-label="'subject'"
170
:group-select="true"
171
label="title"
172
track-by="code"
173
placeholder="Select courses">
174
175
<template #option="{ option }">
176
<div class="course-option">
177
<span class="course-title">{{ option.title }}</span>
178
<span class="course-credits">{{ option.credits }} credits</span>
179
<span class="course-level">Level {{ option.level }}</span>
180
</div>
181
</template>
182
183
<template #tag="{ option, remove }">
184
<span class="course-tag">
185
{{ option.code }}: {{ option.title }}
186
<button @click="remove(option)">×</button>
187
</span>
188
</template>
189
</VueMultiselect>
190
</template>
191
192
<script>
193
export default {
194
data() {
195
return {
196
selectedCourses: [],
197
courseGroups: [
198
{
199
subject: 'Computer Science',
200
totalCredits: 24,
201
courses: [
202
{
203
code: 'CS101',
204
title: 'Introduction to Programming',
205
credits: 4,
206
level: 1,
207
prerequisites: []
208
},
209
{
210
code: 'CS201',
211
title: 'Data Structures',
212
credits: 4,
213
level: 2,
214
prerequisites: ['CS101']
215
}
216
]
217
},
218
{
219
subject: 'Mathematics',
220
totalCredits: 16,
221
courses: [
222
{
223
code: 'MATH101',
224
title: 'Calculus I',
225
credits: 4,
226
level: 1,
227
prerequisites: []
228
},
229
{
230
code: 'MATH201',
231
title: 'Linear Algebra',
232
credits: 4,
233
level: 2,
234
prerequisites: ['MATH101']
235
}
236
]
237
}
238
]
239
}
240
}
241
}
242
</script>
243
244
<style>
245
.course-option {
246
display: flex;
247
justify-content: space-between;
248
align-items: center;
249
padding: 4px 0;
250
}
251
252
.course-title {
253
font-weight: 500;
254
}
255
256
.course-credits, .course-level {
257
font-size: 12px;
258
color: #666;
259
}
260
261
.course-tag {
262
display: inline-flex;
263
align-items: center;
264
gap: 4px;
265
padding: 2px 6px;
266
background: #e3f2fd;
267
border-radius: 3px;
268
font-size: 12px;
269
}
270
</style>
271
```
272
273
### Group Filtering
274
275
Apply search and filtering to grouped options.
276
277
```vue
278
<template>
279
<VueMultiselect
280
v-model="selectedProducts"
281
:options="productGroups"
282
:multiple="true"
283
:searchable="true"
284
:group-values="'products'"
285
:group-label="'category'"
286
:group-select="true"
287
label="name"
288
track-by="sku"
289
placeholder="Search products by category">
290
</VueMultiselect>
291
</template>
292
293
<script>
294
export default {
295
data() {
296
return {
297
selectedProducts: [],
298
productGroups: [
299
{
300
category: 'Electronics',
301
products: [
302
{ sku: 'EL001', name: 'Smartphone', price: 699 },
303
{ sku: 'EL002', name: 'Laptop', price: 1299 },
304
{ sku: 'EL003', name: 'Headphones', price: 199 }
305
]
306
},
307
{
308
category: 'Books',
309
products: [
310
{ sku: 'BK001', name: 'JavaScript Guide', price: 39 },
311
{ sku: 'BK002', name: 'Vue.js Cookbook', price: 45 }
312
]
313
}
314
]
315
}
316
}
317
}
318
</script>
319
```
320
321
### Custom Group Rendering
322
323
Customize the appearance of group headers and options.
324
325
```vue
326
<template>
327
<VueMultiselect
328
v-model="selectedTeamMembers"
329
:options="teams"
330
:multiple="true"
331
:group-values="'members'"
332
:group-label="'teamName'"
333
:group-select="true"
334
label="name"
335
track-by="id">
336
337
<template #beforeList>
338
<div class="team-stats">
339
<strong>{{ selectedTeamMembers.length }}</strong> members selected
340
</div>
341
</template>
342
343
<template #option="{ option, search }">
344
<div class="team-member-option">
345
<img :src="option.avatar" :alt="option.name" class="member-avatar">
346
<div class="member-info">
347
<div class="member-name">{{ option.name }}</div>
348
<div class="member-role">{{ option.role }}</div>
349
<div class="member-email">{{ option.email }}</div>
350
</div>
351
<div class="member-status" :class="option.status">
352
{{ option.status }}
353
</div>
354
</div>
355
</template>
356
357
<template #tag="{ option, remove }">
358
<span class="member-tag">
359
<img :src="option.avatar" :alt="option.name" class="tag-avatar">
360
{{ option.name }}
361
<button @click="remove(option)" class="remove-btn">×</button>
362
</span>
363
</template>
364
</VueMultiselect>
365
</template>
366
367
<script>
368
export default {
369
data() {
370
return {
371
selectedTeamMembers: [],
372
teams: [
373
{
374
teamName: 'Frontend Team',
375
teamLead: 'Alice Johnson',
376
members: [
377
{
378
id: 1,
379
name: 'Alice Johnson',
380
role: 'Team Lead',
381
email: 'alice@company.com',
382
avatar: '/avatars/alice.jpg',
383
status: 'online'
384
},
385
{
386
id: 2,
387
name: 'Bob Smith',
388
role: 'Senior Developer',
389
email: 'bob@company.com',
390
avatar: '/avatars/bob.jpg',
391
status: 'away'
392
}
393
]
394
},
395
{
396
teamName: 'Backend Team',
397
teamLead: 'Charlie Brown',
398
members: [
399
{
400
id: 3,
401
name: 'Charlie Brown',
402
role: 'Team Lead',
403
email: 'charlie@company.com',
404
avatar: '/avatars/charlie.jpg',
405
status: 'online'
406
}
407
]
408
}
409
]
410
}
411
}
412
}
413
</script>
414
415
<style>
416
.team-stats {
417
padding: 8px 12px;
418
background: #f5f5f5;
419
border-bottom: 1px solid #ddd;
420
font-size: 12px;
421
}
422
423
.team-member-option {
424
display: flex;
425
align-items: center;
426
padding: 8px 12px;
427
gap: 12px;
428
}
429
430
.member-avatar, .tag-avatar {
431
width: 32px;
432
height: 32px;
433
border-radius: 50%;
434
object-fit: cover;
435
}
436
437
.tag-avatar {
438
width: 20px;
439
height: 20px;
440
}
441
442
.member-info {
443
flex: 1;
444
}
445
446
.member-name {
447
font-weight: 500;
448
font-size: 14px;
449
}
450
451
.member-role {
452
font-size: 12px;
453
color: #666;
454
}
455
456
.member-email {
457
font-size: 11px;
458
color: #999;
459
}
460
461
.member-status {
462
padding: 2px 6px;
463
border-radius: 10px;
464
font-size: 10px;
465
text-transform: uppercase;
466
}
467
468
.member-status.online {
469
background: #4caf50;
470
color: white;
471
}
472
473
.member-status.away {
474
background: #ff9800;
475
color: white;
476
}
477
478
.member-tag {
479
display: inline-flex;
480
align-items: center;
481
gap: 6px;
482
padding: 4px 8px;
483
background: #e3f2fd;
484
border-radius: 16px;
485
font-size: 12px;
486
}
487
488
.remove-btn {
489
background: none;
490
border: none;
491
cursor: pointer;
492
font-size: 16px;
493
color: #666;
494
padding: 0;
495
margin-left: 4px;
496
}
497
</style>
498
```
499
500
### Group Events
501
502
Events specific to group operations.
503
504
```typescript { .api }
505
/**
506
* Group-related events
507
*/
508
interface GroupEvents {
509
/** Emitted when a group is selected/deselected */
510
'@group-select': (group: any, selectedMembers: any[]) => void;
511
512
/** Emitted when group selection state changes */
513
'@group-change': (group: any, isSelected: boolean) => void;
514
}
515
```
516
517
### Disabled Groups
518
519
Handle disabled state for entire groups or individual options within groups.
520
521
```vue
522
<template>
523
<VueMultiselect
524
v-model="selectedFeatures"
525
:options="featureGroups"
526
:multiple="true"
527
:group-values="'features'"
528
:group-label="'plan'"
529
:group-select="true"
530
label="name"
531
track-by="id">
532
533
<template #option="{ option }">
534
<div class="feature-option" :class="{ disabled: option.disabled }">
535
<span>{{ option.name }}</span>
536
<span v-if="option.disabled" class="disabled-reason">
537
({{ option.disabledReason }})
538
</span>
539
</div>
540
</template>
541
</VueMultiselect>
542
</template>
543
544
<script>
545
export default {
546
data() {
547
return {
548
selectedFeatures: [],
549
featureGroups: [
550
{
551
plan: 'Basic Plan',
552
features: [
553
{ id: 1, name: 'Email Support', disabled: false },
554
{ id: 2, name: 'Basic Analytics', disabled: false }
555
]
556
},
557
{
558
plan: 'Premium Plan',
559
features: [
560
{
561
id: 3,
562
name: 'Priority Support',
563
disabled: true,
564
disabledReason: 'Upgrade required'
565
},
566
{
567
id: 4,
568
name: 'Advanced Analytics',
569
disabled: true,
570
disabledReason: 'Upgrade required'
571
}
572
]
573
}
574
]
575
}
576
}
577
}
578
</script>
579
580
<style>
581
.feature-option.disabled {
582
opacity: 0.5;
583
cursor: not-allowed;
584
}
585
586
.disabled-reason {
587
font-size: 11px;
588
color: #999;
589
font-style: italic;
590
}
591
</style>
592
```