0
# Component API
1
2
The component API provides Vue components for declarative context menu construction. This approach integrates seamlessly with Vue templates and is ideal for static menus, form-based interfaces, and component-driven architectures.
3
4
## Capabilities
5
6
### ContextMenu Component
7
8
Main context menu container component that manages menu display, positioning, and lifecycle.
9
10
```typescript { .api }
11
declare component ContextMenu {
12
props: {
13
/** Menu configuration options */
14
options: MenuOptions;
15
/** Show/hide menu state */
16
show: boolean;
17
};
18
emits: {
19
/** Emitted when show state should change */
20
'update:show': (show: boolean) => boolean;
21
/** Emitted when menu closes */
22
'close': () => boolean;
23
};
24
slots: {
25
/** Default slot for menu items */
26
default: {};
27
/** Custom item renderer slot */
28
itemRender: {
29
label: string;
30
icon: string;
31
disabled: boolean;
32
onClick: (e: MouseEvent) => void;
33
onMouseEnter: (e: MouseEvent) => void;
34
};
35
/** Custom separator renderer slot */
36
separatorRender: {};
37
/** Custom icon renderer slot */
38
itemIconRender: { label: string; icon: string; };
39
/** Custom label renderer slot */
40
itemLabelRender: { label: string; };
41
/** Custom shortcut renderer slot */
42
itemShortcutRender: { shortcut: string; };
43
/** Custom right arrow renderer slot */
44
itemRightArrowRender: {};
45
/** Custom check mark renderer slot */
46
itemCheckRender: { checked: boolean; };
47
};
48
}
49
```
50
51
**Usage Examples:**
52
53
```vue
54
<template>
55
<!-- Basic component usage -->
56
<div @contextmenu="onRightClick">
57
<context-menu v-model:show="showMenu" :options="menuOptions">
58
<context-menu-item label="Copy" icon="copy" @click="handleCopy" />
59
<context-menu-item label="Paste" icon="paste" @click="handlePaste" />
60
<context-menu-separator />
61
<context-menu-item label="Delete" icon="delete" @click="handleDelete" />
62
</context-menu>
63
</div>
64
65
<!-- Advanced usage with nested menus -->
66
<div @contextmenu="onAdvancedRightClick">
67
<context-menu
68
v-model:show="showAdvancedMenu"
69
:options="advancedOptions"
70
@close="onMenuClose"
71
>
72
<context-menu-item label="File Operations" icon="folder">
73
<template #submenu="{ show }">
74
<context-menu-group v-if="show" label="File">
75
<context-menu-item label="New" shortcut="Ctrl+N" @click="createNew" />
76
<context-menu-item label="Open" shortcut="Ctrl+O" @click="openFile" />
77
<context-menu-separator />
78
<context-menu-item label="Save" shortcut="Ctrl+S" @click="saveFile" />
79
</context-menu-group>
80
</template>
81
</context-menu-item>
82
83
<context-menu-item label="Edit" :disabled="!canEdit" @click="editItem" />
84
</context-menu>
85
</div>
86
87
<!-- Custom rendering with slots -->
88
<context-menu v-model:show="showCustomMenu" :options="customOptions">
89
<template #itemRender="{ label, icon, onClick, onMouseEnter, disabled }">
90
<div
91
:class="['custom-menu-item', { disabled }]"
92
@click="onClick"
93
@mouseenter="onMouseEnter"
94
>
95
<img v-if="icon" :src="icon" class="custom-icon" />
96
<span class="custom-label">{{ label }}</span>
97
</div>
98
</template>
99
100
<context-menu-item label="Custom Item" icon="/icons/custom.png" />
101
</context-menu>
102
</template>
103
104
<script setup>
105
import { ref } from 'vue';
106
107
const showMenu = ref(false);
108
const menuOptions = ref({
109
x: 0,
110
y: 0,
111
theme: 'default',
112
zIndex: 1000
113
});
114
115
function onRightClick(e) {
116
e.preventDefault();
117
menuOptions.value.x = e.clientX;
118
menuOptions.value.y = e.clientY;
119
showMenu.value = true;
120
}
121
122
function onMenuClose() {
123
console.log('Menu closed');
124
}
125
</script>
126
```
127
128
### ContextMenuItem Component
129
130
Individual menu item component with support for icons, labels, shortcuts, and click handling.
131
132
```typescript { .api }
133
declare component ContextMenuItem {
134
props: {
135
/** Menu item label text, VNode, or render function */
136
label?: string | VNode | ((label: string) => VNode);
137
/** Icon CSS class, VNode, or render function */
138
icon?: string | VNode | ((icon: string) => VNode);
139
/** Custom icon font class name */
140
iconFontClass?: string;
141
/** SVG symbol icon reference */
142
svgIcon?: string;
143
/** SVG element properties */
144
svgProps?: SVGAttributes;
145
/** Disable the menu item */
146
disabled?: boolean;
147
/** Hide the menu item */
148
hidden?: boolean;
149
/** Show check mark */
150
checked?: boolean;
151
/** Shortcut key display text */
152
shortcut?: string;
153
/** Reserve icon width space */
154
preserveIconWidth?: boolean;
155
/** Custom CSS class */
156
customClass?: string;
157
/** Custom render function */
158
customRender?: VNode | ((item: MenuItem) => VNode);
159
/** Click handler function */
160
clickHandler?: (e: MouseEvent | KeyboardEvent) => void;
161
/** Show right arrow indicator for submenus */
162
showRightArrow?: boolean;
163
/** Indicates if item has children/submenu */
164
hasChildren?: boolean;
165
/** Should close menu when this item is clicked */
166
clickClose?: boolean;
167
/** Allow click event when item has children */
168
clickableWhenHasChildren?: boolean;
169
/** Raw MenuItem data object */
170
rawMenuItem?: MenuItem;
171
};
172
emits: {
173
/** Emitted when item is clicked */
174
'click': (e: MouseEvent | KeyboardEvent) => boolean;
175
/** Emitted when submenu opens */
176
'subMenuOpen': () => boolean;
177
/** Emitted when submenu closes */
178
'subMenuClose': () => boolean;
179
};
180
slots: {
181
/** Default slot content */
182
default: {};
183
/** Icon slot */
184
icon: {};
185
/** Label slot */
186
label: {};
187
/** Shortcut slot */
188
shortcut: {};
189
/** Right arrow slot for submenus */
190
rightArrow: {};
191
/** Check mark slot */
192
check: {};
193
/** Submenu slot */
194
submenu: { context: MenuItemContext; show: boolean; };
195
};
196
}
197
```
198
199
**Usage Examples:**
200
201
```vue
202
<template>
203
<!-- Basic menu items -->
204
<context-menu-item label="Simple Item" @click="handleClick" />
205
206
<!-- Item with icon and shortcut -->
207
<context-menu-item
208
label="Save File"
209
icon="save-icon"
210
shortcut="Ctrl+S"
211
@click="saveFile"
212
/>
213
214
<!-- Disabled and checked items -->
215
<context-menu-item
216
label="Readonly Mode"
217
:disabled="!canEdit"
218
:checked="isReadonly"
219
@click="toggleReadonly"
220
/>
221
222
<!-- Item with custom icon slot -->
223
<context-menu-item label="Custom Icon" @click="handleCustom">
224
<template #icon>
225
<svg class="custom-svg-icon">
226
<use xlink:href="#my-icon"></use>
227
</svg>
228
</template>
229
</context-menu-item>
230
231
<!-- Item with submenu -->
232
<context-menu-item label="Recent Files">
233
<template #submenu="{ show, context }">
234
<context-menu-group v-if="show" label="Recent">
235
<context-menu-item
236
v-for="file in recentFiles"
237
:key="file.id"
238
:label="file.name"
239
@click="() => openFile(file)"
240
/>
241
</context-menu-group>
242
</template>
243
</context-menu-item>
244
245
<!-- Item with custom rendering -->
246
<context-menu-item
247
label="Custom Render"
248
:custom-render="customItemRenderer"
249
@click="handleCustomRender"
250
/>
251
</template>
252
253
<script setup>
254
import { h } from 'vue';
255
256
function customItemRenderer(item) {
257
return h('div', { class: 'custom-item-wrapper' }, [
258
h('span', { class: 'custom-prefix' }, '★'),
259
h('span', item.label),
260
h('span', { class: 'custom-suffix' }, '→')
261
]);
262
}
263
</script>
264
```
265
266
### ContextMenuSeparator Component
267
268
Visual separator component for grouping related menu items.
269
270
```typescript { .api }
271
declare component ContextMenuSeparator {
272
// No props or events
273
}
274
```
275
276
**Usage:**
277
278
```vue
279
<template>
280
<context-menu>
281
<context-menu-item label="Copy" @click="copy" />
282
<context-menu-item label="Paste" @click="paste" />
283
284
<!-- Visual separator -->
285
<context-menu-separator />
286
287
<context-menu-item label="Delete" @click="delete" />
288
</context-menu>
289
</template>
290
```
291
292
### ContextMenuGroup Component
293
294
Container component for creating nested submenus with optional group labels.
295
296
```typescript { .api }
297
declare component ContextMenuGroup {
298
props: {
299
/** Group label text */
300
label?: string;
301
/** Icon CSS class or image path */
302
icon?: string;
303
/** Custom icon font class name */
304
iconFontClass?: string;
305
/** SVG symbol icon reference */
306
svgIcon?: string;
307
/** SVG element properties */
308
svgProps?: SVGAttributes;
309
/** Disable the group */
310
disabled?: boolean;
311
/** Hide the group */
312
hidden?: boolean;
313
/** Show check mark */
314
checked?: boolean;
315
/** Shortcut key display text */
316
shortcut?: string;
317
/** Reserve fixed-width icon area */
318
preserveIconWidth?: boolean;
319
/** Show right arrow indicator */
320
showRightArrow?: boolean;
321
/** Close menu when group is clicked */
322
clickClose?: boolean;
323
/** Adjust submenu position */
324
adjustSubMenuPosition?: boolean;
325
/** Maximum height of submenu */
326
maxHeight?: number | string;
327
/** Maximum width of submenu */
328
maxWidth?: number | string;
329
/** Minimum width of submenu */
330
minWidth?: number | string;
331
/** Custom CSS class */
332
customClass?: string;
333
/** Click handler function */
334
clickHandler?: () => void;
335
};
336
slots: {
337
/** Default slot for child menu items */
338
default: {};
339
};
340
}
341
```
342
343
**Usage Examples:**
344
345
```vue
346
<template>
347
<!-- Basic group with label -->
348
<context-menu-group label="File Operations">
349
<context-menu-item label="New" @click="createNew" />
350
<context-menu-item label="Open" @click="openFile" />
351
<context-menu-item label="Save" @click="saveFile" />
352
</context-menu-group>
353
354
<!-- Nested groups -->
355
<context-menu-group label="Edit">
356
<context-menu-item label="Undo" @click="undo" />
357
<context-menu-item label="Redo" @click="redo" />
358
359
<context-menu-group label="Selection">
360
<context-menu-item label="Select All" @click="selectAll" />
361
<context-menu-item label="Select None" @click="selectNone" />
362
<context-menu-item label="Invert Selection" @click="invertSelection" />
363
</context-menu-group>
364
</context-menu-group>
365
366
<!-- Dynamic group content -->
367
<context-menu-group label="Recent Projects">
368
<context-menu-item
369
v-for="project in recentProjects"
370
:key="project.id"
371
:label="project.name"
372
:icon="project.icon"
373
@click="() => openProject(project)"
374
/>
375
<context-menu-separator v-if="recentProjects.length > 0" />
376
<context-menu-item label="Clear Recent" @click="clearRecent" />
377
</context-menu-group>
378
</template>
379
```
380
381
## Component Integration Patterns
382
383
### Reactive Menu State
384
385
```vue
386
<template>
387
<div class="editor" @contextmenu="showContextMenu">
388
<context-menu v-model:show="menuVisible" :options="menuConfig">
389
<context-menu-item
390
label="Cut"
391
:disabled="!hasSelection"
392
shortcut="Ctrl+X"
393
@click="cutText"
394
/>
395
<context-menu-item
396
label="Copy"
397
:disabled="!hasSelection"
398
shortcut="Ctrl+C"
399
@click="copyText"
400
/>
401
<context-menu-item
402
label="Paste"
403
:disabled="!canPaste"
404
shortcut="Ctrl+V"
405
@click="pasteText"
406
/>
407
<context-menu-separator />
408
<context-menu-item
409
label="Select All"
410
shortcut="Ctrl+A"
411
@click="selectAllText"
412
/>
413
</context-menu>
414
</div>
415
</template>
416
417
<script setup>
418
import { ref, computed } from 'vue';
419
420
const menuVisible = ref(false);
421
const selectedText = ref('');
422
const clipboard = ref('');
423
424
const menuConfig = ref({
425
x: 0,
426
y: 0,
427
theme: 'default'
428
});
429
430
const hasSelection = computed(() => selectedText.value.length > 0);
431
const canPaste = computed(() => clipboard.value.length > 0);
432
433
function showContextMenu(e) {
434
e.preventDefault();
435
menuConfig.value.x = e.clientX;
436
menuConfig.value.y = e.clientY;
437
menuVisible.value = true;
438
}
439
</script>
440
```
441
442
### Menu with Form Integration
443
444
```vue
445
<template>
446
<form @submit="submitForm">
447
<input
448
v-model="formData.name"
449
@contextmenu="showFieldMenu"
450
data-field="name"
451
/>
452
453
<context-menu v-model:show="fieldMenuVisible" :options="fieldMenuConfig">
454
<context-menu-item label="Clear Field" @click="clearCurrentField" />
455
<context-menu-item label="Reset to Default" @click="resetCurrentField" />
456
<context-menu-separator />
457
<context-menu-item label="Validate Field" @click="validateCurrentField" />
458
<context-menu-group label="Auto-fill">
459
<context-menu-item
460
v-for="suggestion in currentFieldSuggestions"
461
:key="suggestion"
462
:label="suggestion"
463
@click="() => setFieldValue(suggestion)"
464
/>
465
</context-menu-group>
466
</context-menu>
467
</form>
468
</template>
469
470
<script setup>
471
import { ref, computed } from 'vue';
472
473
const fieldMenuVisible = ref(false);
474
const currentField = ref('');
475
const formData = ref({ name: '', email: '' });
476
477
const currentFieldSuggestions = computed(() => {
478
if (currentField.value === 'name') {
479
return ['John Doe', 'Jane Smith', 'Admin User'];
480
}
481
return [];
482
});
483
484
function showFieldMenu(e) {
485
e.preventDefault();
486
currentField.value = e.target.dataset.field;
487
fieldMenuConfig.value.x = e.clientX;
488
fieldMenuConfig.value.y = e.clientY;
489
fieldMenuVisible.value = true;
490
}
491
</script>
492
```
493
494
## Component Reference Interface
495
496
When using template refs with context menu components:
497
498
```typescript { .api }
499
interface ContextMenuComponentRef extends ContextMenuInstance {
500
/** Close the menu */
501
closeMenu(): void;
502
/** Check if menu is closed */
503
isClosed(): boolean;
504
/** Get menu reference for advanced control */
505
getMenuRef(): ContextSubMenuInstance | undefined;
506
/** Get menu dimensions */
507
getMenuDimensions(): { width: number, height: number };
508
}
509
510
interface ContextMenuGroupRef {
511
/** Get submenu instance */
512
getSubMenuRef(): ContextSubMenuInstance;
513
/** Get menu item reference */
514
getMenuItemRef(): ContextSubMenuInstance;
515
}
516
```
517
518
**Usage with Template Refs:**
519
520
```vue
521
<template>
522
<context-menu ref="menuRef" v-model:show="show" :options="options">
523
<!-- menu items -->
524
</context-menu>
525
526
<button @click="controlMenu">Control Menu</button>
527
</template>
528
529
<script setup>
530
import { ref } from 'vue';
531
532
const menuRef = ref<ContextMenuComponentRef>();
533
534
function controlMenu() {
535
if (menuRef.value) {
536
if (menuRef.value.isClosed()) {
537
// Menu is closed, could trigger show
538
} else {
539
// Menu is open, close it
540
menuRef.value.closeMenu();
541
}
542
}
543
}
544
</script>
545
```