0
# Themes and Styling
1
2
Vue3 Context Menu provides a comprehensive theming system with built-in themes and extensive customization options. The library includes multiple pre-designed themes with light and dark variants, plus support for custom themes through CSS variables and class overrides.
3
4
## Capabilities
5
6
### Built-in Themes
7
8
The library includes several built-in themes designed to match different design systems and operating system styles.
9
10
```typescript { .api }
11
type ThemeNames =
12
| 'default'
13
| 'default dark'
14
| 'flat'
15
| 'flat dark'
16
| 'win10'
17
| 'win10 dark'
18
| 'mac'
19
| 'mac dark';
20
```
21
22
**Theme Usage:**
23
24
```typescript
25
// Functional API
26
ContextMenu.showContextMenu({
27
x: e.x,
28
y: e.y,
29
theme: 'win10 dark',
30
items: [...]
31
});
32
33
// Component API
34
const menuOptions = {
35
theme: 'mac',
36
x: 100,
37
y: 100
38
};
39
```
40
41
```vue
42
<template>
43
<context-menu :options="menuOptions" v-model:show="show">
44
<!-- menu items -->
45
</context-menu>
46
</template>
47
48
<script setup>
49
const menuOptions = {
50
theme: 'flat dark',
51
x: 0,
52
y: 0
53
};
54
</script>
55
```
56
57
### Theme Descriptions
58
59
#### Default Theme
60
Clean, modern appearance suitable for most applications.
61
62
- **'default'**: Light variant with subtle shadows and rounded corners
63
- **'default dark'**: Dark variant with light text on dark backgrounds
64
65
#### Flat Theme
66
Minimalist design with flat elements and subtle borders.
67
68
- **'flat'**: Light flat design with minimal shadows
69
- **'flat dark'**: Dark flat design with high contrast
70
71
#### Windows 10 Theme
72
Matches Windows 10 context menu styling.
73
74
- **'win10'**: Light Windows 10 style with system-like appearance
75
- **'win10 dark'**: Dark Windows 10 style matching dark mode
76
77
#### macOS Theme
78
Follows macOS design guidelines and visual style.
79
80
- **'mac'**: Light macOS style with system-like rounded corners
81
- **'mac dark'**: Dark macOS style matching macOS dark mode
82
83
### Theme Examples
84
85
```vue
86
<template>
87
<div class="theme-showcase">
88
<!-- Default theme -->
89
<button @click="showDefaultMenu">Default Theme</button>
90
91
<!-- Windows 10 theme -->
92
<button @click="showWin10Menu">Windows 10 Theme</button>
93
94
<!-- macOS theme -->
95
<button @click="showMacMenu">macOS Theme</button>
96
97
<!-- Flat theme -->
98
<button @click="showFlatMenu">Flat Theme</button>
99
</div>
100
</template>
101
102
<script setup>
103
import ContextMenu from '@imengyu/vue3-context-menu';
104
105
function showDefaultMenu(e) {
106
ContextMenu.showContextMenu({
107
x: e.clientX,
108
y: e.clientY,
109
theme: 'default',
110
items: getThemeMenuItems()
111
});
112
}
113
114
function showWin10Menu(e) {
115
ContextMenu.showContextMenu({
116
x: e.clientX,
117
y: e.clientY,
118
theme: 'win10',
119
items: getThemeMenuItems()
120
});
121
}
122
123
function showMacMenu(e) {
124
ContextMenu.showContextMenu({
125
x: e.clientX,
126
y: e.clientY,
127
theme: 'mac',
128
items: getThemeMenuItems()
129
});
130
}
131
132
function showFlatMenu(e) {
133
ContextMenu.showContextMenu({
134
x: e.clientX,
135
y: e.clientY,
136
theme: 'flat',
137
items: getThemeMenuItems()
138
});
139
}
140
141
function getThemeMenuItems() {
142
return [
143
{ label: 'New File', icon: 'file-icon' },
144
{ label: 'Open File', icon: 'folder-icon' },
145
{ divided: true, label: 'Settings', icon: 'settings-icon' }
146
];
147
}
148
</script>
149
```
150
151
## Custom Themes
152
153
### Creating Custom Themes
154
155
Create custom themes by defining CSS classes and overriding CSS variables.
156
157
```css
158
/* Custom theme definition */
159
.mx-context-menu.my-custom-theme {
160
--mx-menu-backgroud: #2d3748;
161
--mx-menu-border-color: #4a5568;
162
--mx-menu-shadow-color: rgba(0, 0, 0, 0.3);
163
--mx-menu-hover-backgroud: #4a5568;
164
--mx-menu-text-color: #e2e8f0;
165
--mx-menu-hover-text-color: #ffffff;
166
--mx-menu-disabled-text-color: #718096;
167
--mx-menu-separator-color: #4a5568;
168
--mx-menu-placeholder-width: 24px;
169
170
/* Menu container styling */
171
padding: 6px 0;
172
border-radius: 8px;
173
box-shadow: 0 4px 12px var(--mx-menu-shadow-color);
174
border: 1px solid var(--mx-menu-border-color);
175
background: var(--mx-menu-backgroud);
176
177
/* Menu item styling */
178
.mx-context-menu-item {
179
padding: 8px 16px;
180
margin: 2px 4px;
181
border-radius: 4px;
182
color: var(--mx-menu-text-color);
183
184
&:hover:not(.disabled) {
185
background: var(--mx-menu-hover-backgroud);
186
color: var(--mx-menu-hover-text-color);
187
}
188
189
&.disabled {
190
color: var(--mx-menu-disabled-text-color);
191
opacity: 0.6;
192
}
193
}
194
195
/* Separator styling */
196
.mx-context-menu-separator {
197
border-color: var(--mx-menu-separator-color);
198
margin: 4px 8px;
199
}
200
}
201
```
202
203
**Usage of Custom Theme:**
204
205
```typescript
206
ContextMenu.showContextMenu({
207
x: e.x,
208
y: e.y,
209
theme: 'my-custom-theme',
210
items: [...]
211
});
212
```
213
214
### CSS Variables Reference
215
216
All available CSS variables for theme customization:
217
218
```css { .api }
219
.mx-context-menu {
220
/* Background colors */
221
--mx-menu-backgroud: #ffffff;
222
--mx-menu-hover-backgroud: #f0f0f0;
223
--mx-menu-active-backgroud: #e0e0e0;
224
225
/* Text colors */
226
--mx-menu-text-color: #333333;
227
--mx-menu-hover-text-color: #333333;
228
--mx-menu-disabled-text-color: #999999;
229
230
/* Border and shadow */
231
--mx-menu-border-color: #e0e0e0;
232
--mx-menu-shadow-color: rgba(0, 0, 0, 0.15);
233
234
/* Separator */
235
--mx-menu-separator-color: #e0e0e0;
236
237
/* Layout */
238
--mx-menu-placeholder-width: 20px;
239
--mx-menu-padding: 4px 0;
240
--mx-menu-item-padding: 6px 12px;
241
--mx-menu-border-radius: 4px;
242
243
/* Icons */
244
--mx-menu-icon-size: 16px;
245
--mx-menu-check-size: 14px;
246
--mx-menu-arrow-size: 12px;
247
248
/* Transitions */
249
--mx-menu-transition-duration: 0.15s;
250
}
251
```
252
253
### Advanced Custom Theme Example
254
255
```css
256
/* Futuristic theme with gradients and animations */
257
.mx-context-menu.futuristic-theme {
258
--mx-menu-backgroud: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
259
--mx-menu-hover-backgroud: rgba(255, 255, 255, 0.1);
260
--mx-menu-text-color: #ffffff;
261
--mx-menu-shadow-color: rgba(102, 126, 234, 0.3);
262
--mx-menu-border-color: rgba(255, 255, 255, 0.2);
263
264
padding: 8px 0;
265
border-radius: 12px;
266
backdrop-filter: blur(10px);
267
border: 1px solid var(--mx-menu-border-color);
268
box-shadow:
269
0 8px 32px var(--mx-menu-shadow-color),
270
inset 0 1px 0 rgba(255, 255, 255, 0.1);
271
272
.mx-context-menu-item {
273
padding: 10px 16px;
274
margin: 2px 6px;
275
border-radius: 6px;
276
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
277
position: relative;
278
overflow: hidden;
279
280
&::before {
281
content: '';
282
position: absolute;
283
top: 0;
284
left: -100%;
285
width: 100%;
286
height: 100%;
287
background: linear-gradient(
288
90deg,
289
transparent,
290
rgba(255, 255, 255, 0.1),
291
transparent
292
);
293
transition: left 0.5s;
294
}
295
296
&:hover:not(.disabled) {
297
background: var(--mx-menu-hover-backgroud);
298
transform: translateX(4px);
299
300
&::before {
301
left: 100%;
302
}
303
}
304
305
.label {
306
font-weight: 500;
307
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
308
}
309
}
310
}
311
```
312
313
## Dynamic Theme Switching
314
315
### Theme Switching Implementation
316
317
```vue
318
<template>
319
<div>
320
<div class="theme-controls">
321
<select v-model="currentTheme" @change="updateTheme">
322
<option value="default">Default Light</option>
323
<option value="default dark">Default Dark</option>
324
<option value="win10">Windows 10</option>
325
<option value="win10 dark">Windows 10 Dark</option>
326
<option value="mac">macOS</option>
327
<option value="mac dark">macOS Dark</option>
328
<option value="flat">Flat</option>
329
<option value="flat dark">Flat Dark</option>
330
</select>
331
</div>
332
333
<div @contextmenu="showThemedMenu">
334
Right-click to see themed menu
335
</div>
336
</div>
337
</template>
338
339
<script setup>
340
import { ref } from 'vue';
341
import ContextMenu from '@imengyu/vue3-context-menu';
342
343
const currentTheme = ref('default');
344
345
function showThemedMenu(e) {
346
e.preventDefault();
347
348
ContextMenu.showContextMenu({
349
x: e.clientX,
350
y: e.clientY,
351
theme: currentTheme.value,
352
items: [
353
{ label: 'New', icon: 'new-icon' },
354
{ label: 'Open', icon: 'open-icon' },
355
{ label: 'Save', icon: 'save-icon', shortcut: 'Ctrl+S' },
356
{ divided: true, label: 'Settings', icon: 'settings-icon' }
357
]
358
});
359
}
360
361
function updateTheme() {
362
// Theme will be applied to next menu
363
console.log(`Theme changed to: ${currentTheme.value}`);
364
}
365
</script>
366
```
367
368
### System Theme Detection
369
370
```vue
371
<template>
372
<div @contextmenu="showSystemThemedMenu">
373
Right-click for system-matched theme
374
</div>
375
</template>
376
377
<script setup>
378
import { ref, onMounted } from 'vue';
379
import ContextMenu from '@imengyu/vue3-context-menu';
380
381
const systemTheme = ref('default');
382
383
function detectSystemTheme() {
384
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
385
systemTheme.value = 'default dark';
386
} else {
387
systemTheme.value = 'default';
388
}
389
}
390
391
function showSystemThemedMenu(e) {
392
e.preventDefault();
393
394
ContextMenu.showContextMenu({
395
x: e.clientX,
396
y: e.clientY,
397
theme: systemTheme.value,
398
items: getMenuItems()
399
});
400
}
401
402
onMounted(() => {
403
detectSystemTheme();
404
405
// Listen for system theme changes
406
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
407
mediaQuery.addEventListener('change', detectSystemTheme);
408
});
409
</script>
410
```
411
412
## Icon Integration
413
414
### Icon Font Classes
415
416
Configure global icon font classes for consistent icon display:
417
418
```typescript { .api }
419
interface IconConfiguration {
420
/** Global icon font class name */
421
iconFontClass?: string;
422
/** Reserve icon width for items without icons */
423
preserveIconWidth?: boolean;
424
}
425
```
426
427
**Usage Examples:**
428
429
```typescript
430
// Global icon font configuration
431
ContextMenu.showContextMenu({
432
x: e.x,
433
y: e.y,
434
iconFontClass: 'fa', // Font Awesome
435
preserveIconWidth: true,
436
items: [
437
{ label: 'New', icon: 'fa-file' },
438
{ label: 'Open', icon: 'fa-folder-open' },
439
{ label: 'Save', icon: 'fa-save' }
440
]
441
});
442
443
// Per-item icon font class
444
ContextMenu.showContextMenu({
445
x: e.x,
446
y: e.y,
447
items: [
448
{
449
label: 'Custom Icon',
450
icon: 'custom-icon',
451
iconFontClass: 'material-icons'
452
}
453
]
454
});
455
```
456
457
### SVG Icons
458
459
Support for SVG symbols and custom SVG icons:
460
461
```typescript
462
// SVG symbol icons
463
ContextMenu.showContextMenu({
464
x: e.x,
465
y: e.y,
466
items: [
467
{
468
label: 'Home',
469
svgIcon: '#icon-home',
470
svgProps: {
471
width: 16,
472
height: 16,
473
fill: 'currentColor'
474
}
475
}
476
]
477
});
478
```
479
480
### Custom Icon Components
481
482
```vue
483
<template>
484
<context-menu>
485
<context-menu-item label="Custom Icon">
486
<template #icon>
487
<svg class="custom-icon" viewBox="0 0 24 24">
488
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
489
</svg>
490
</template>
491
</context-menu-item>
492
</context-menu>
493
</template>
494
495
<style scoped>
496
.custom-icon {
497
width: 16px;
498
height: 16px;
499
fill: currentColor;
500
}
501
</style>
502
```