0
# Menu Bar
1
2
The MenuBar component provides a traditional horizontal menu bar interface similar to desktop applications. It supports both expanded and collapsed (mini) modes, with dropdown context menus for each menu item.
3
4
## Capabilities
5
6
### MenuBar Component
7
8
Horizontal menu bar component that displays menu items and shows dropdown context menus when clicked.
9
10
```typescript { .api }
11
declare component MenuBar {
12
props: {
13
/** Menu bar configuration options */
14
options: MenuBarOptions;
15
};
16
slots: {
17
/** Content before menu items */
18
prefix: {};
19
/** Content after menu items */
20
suffix: {};
21
};
22
}
23
24
interface MenuBarOptions extends Omit<MenuOptions, 'x'|'y'|'getContainer'> {
25
/** Whether the menu bar is in collapsed/mini mode */
26
mini?: boolean;
27
/** Popup direction for dropdown menus in collapsed state */
28
barPopDirection?: MenuPopDirection;
29
/** Array of top-level menu items */
30
items?: MenuItem[];
31
/** Menu theme */
32
theme?: string;
33
/** Other MenuOptions properties... */
34
}
35
```
36
37
**Usage Examples:**
38
39
```vue
40
<template>
41
<!-- Basic menu bar -->
42
<menu-bar :options="basicMenuOptions" />
43
44
<!-- Menu bar with prefix/suffix slots -->
45
<menu-bar :options="advancedMenuOptions">
46
<template #prefix>
47
<div class="app-logo">
48
<img src="/logo.png" alt="App Logo" />
49
</div>
50
</template>
51
52
<template #suffix>
53
<div class="menu-actions">
54
<button @click="showSettings">Settings</button>
55
<button @click="showHelp">Help</button>
56
</div>
57
</template>
58
</menu-bar>
59
60
<!-- Collapsed/mini menu bar -->
61
<menu-bar :options="miniMenuOptions" />
62
</template>
63
64
<script setup>
65
import { ref } from 'vue';
66
67
// Basic menu bar configuration
68
const basicMenuOptions = ref({
69
theme: 'default',
70
items: [
71
{
72
label: 'File',
73
children: [
74
{ label: 'New', shortcut: 'Ctrl+N', onClick: createNew },
75
{ label: 'Open', shortcut: 'Ctrl+O', onClick: openFile },
76
{ label: 'Save', shortcut: 'Ctrl+S', onClick: saveFile },
77
{ divided: true, label: 'Exit', onClick: exitApp }
78
]
79
},
80
{
81
label: 'Edit',
82
children: [
83
{ label: 'Undo', shortcut: 'Ctrl+Z', onClick: undo },
84
{ label: 'Redo', shortcut: 'Ctrl+Y', onClick: redo },
85
{ divided: true, label: 'Cut', shortcut: 'Ctrl+X', onClick: cut },
86
{ label: 'Copy', shortcut: 'Ctrl+C', onClick: copy },
87
{ label: 'Paste', shortcut: 'Ctrl+V', onClick: paste }
88
]
89
},
90
{
91
label: 'View',
92
children: [
93
{ label: 'Zoom In', shortcut: 'Ctrl++', onClick: zoomIn },
94
{ label: 'Zoom Out', shortcut: 'Ctrl+-', onClick: zoomOut },
95
{ label: 'Reset Zoom', shortcut: 'Ctrl+0', onClick: resetZoom }
96
]
97
}
98
]
99
});
100
101
// Advanced menu bar with dynamic content
102
const advancedMenuOptions = ref({
103
theme: 'win10',
104
minWidth: 150,
105
keyboardControl: true,
106
items: [
107
{
108
label: 'File',
109
children: [
110
{ label: 'New Project', onClick: createProject },
111
{
112
label: 'Recent Projects',
113
children: getRecentProjects() // Dynamic submenu
114
},
115
{ divided: true, label: 'Import', onClick: importData },
116
{ label: 'Export', onClick: exportData }
117
]
118
},
119
{
120
label: 'Tools',
121
children: [
122
{ label: 'Preferences', onClick: showPreferences },
123
{ label: 'Extensions', onClick: showExtensions },
124
{
125
label: 'Developer',
126
children: [
127
{ label: 'Console', onClick: showConsole },
128
{ label: 'Debugger', onClick: showDebugger }
129
]
130
}
131
]
132
}
133
]
134
});
135
136
// Mini/collapsed menu bar
137
const miniMenuOptions = ref({
138
mini: true,
139
theme: 'flat dark',
140
barPopDirection: 'bl',
141
items: [
142
{
143
label: 'Menu', // This label is not shown in mini mode
144
children: [
145
{ label: 'File Operations', children: getFileOperations() },
146
{ label: 'Edit Operations', children: getEditOperations() },
147
{ label: 'View Options', children: getViewOptions() },
148
{ divided: true, label: 'Settings', onClick: showSettings },
149
{ label: 'About', onClick: showAbout }
150
]
151
}
152
]
153
});
154
155
function getRecentProjects() {
156
return [
157
{ label: 'Project Alpha', onClick: () => openProject('alpha') },
158
{ label: 'Project Beta', onClick: () => openProject('beta') },
159
{ label: 'Project Gamma', onClick: () => openProject('gamma') }
160
];
161
}
162
</script>
163
```
164
165
### Menu Bar Modes
166
167
The MenuBar component supports two display modes:
168
169
#### Expanded Mode (Default)
170
171
Shows all top-level menu items horizontally across the bar.
172
173
```typescript { .api }
174
interface ExpandedMenuBarConfig {
175
mini: false; // or undefined
176
items: MenuItem[]; // Multiple top-level items displayed
177
}
178
```
179
180
#### Mini/Collapsed Mode
181
182
Shows a single menu button that opens a dropdown containing all menu items.
183
184
```typescript { .api }
185
interface MiniMenuBarConfig {
186
mini: true;
187
items: MenuItem[]; // All items shown in single dropdown
188
barPopDirection?: MenuPopDirection; // Direction for dropdown
189
}
190
```
191
192
**Mode Comparison:**
193
194
```vue
195
<template>
196
<!-- Expanded mode - shows "File", "Edit", "View" horizontally -->
197
<menu-bar :options="expandedOptions" />
198
199
<!-- Mini mode - shows single hamburger menu button -->
200
<menu-bar :options="miniOptions" />
201
</template>
202
203
<script setup>
204
const expandedOptions = {
205
mini: false,
206
items: [
207
{ label: 'File', children: [...] },
208
{ label: 'Edit', children: [...] },
209
{ label: 'View', children: [...] }
210
]
211
};
212
213
const miniOptions = {
214
mini: true,
215
barPopDirection: 'bl',
216
items: [
217
{
218
label: 'Menu', // Not displayed in mini mode
219
children: [
220
{ label: 'File', children: [...] },
221
{ label: 'Edit', children: [...] },
222
{ label: 'View', children: [...] }
223
]
224
}
225
]
226
};
227
</script>
228
```
229
230
## Advanced Menu Bar Patterns
231
232
### Responsive Menu Bar
233
234
```vue
235
<template>
236
<menu-bar :options="responsiveMenuOptions" />
237
</template>
238
239
<script setup>
240
import { ref, computed, onMounted, onUnmounted } from 'vue';
241
242
const screenWidth = ref(window.innerWidth);
243
244
const responsiveMenuOptions = computed(() => ({
245
mini: screenWidth.value < 768, // Mini mode on mobile
246
theme: screenWidth.value < 768 ? 'flat' : 'default',
247
barPopDirection: 'bl',
248
items: getMenuItems()
249
}));
250
251
function updateScreenWidth() {
252
screenWidth.value = window.innerWidth;
253
}
254
255
onMounted(() => {
256
window.addEventListener('resize', updateScreenWidth);
257
});
258
259
onUnmounted(() => {
260
window.removeEventListener('resize', updateScreenWidth);
261
});
262
</script>
263
```
264
265
### Menu Bar with State Management
266
267
```vue
268
<template>
269
<menu-bar :options="stateAwareMenuOptions" />
270
</template>
271
272
<script setup>
273
import { ref, computed } from 'vue';
274
275
const isProjectOpen = ref(false);
276
const hasSelection = ref(false);
277
const canUndo = ref(false);
278
const canRedo = ref(false);
279
280
const stateAwareMenuOptions = computed(() => ({
281
theme: 'win10',
282
items: [
283
{
284
label: 'File',
285
children: [
286
{ label: 'New Project', onClick: createProject },
287
{ label: 'Open Project', onClick: openProject },
288
{
289
label: 'Close Project',
290
disabled: !isProjectOpen.value,
291
onClick: closeProject
292
},
293
{ divided: true, label: 'Save', shortcut: 'Ctrl+S', onClick: save },
294
{
295
label: 'Save As...',
296
disabled: !isProjectOpen.value,
297
onClick: saveAs
298
}
299
]
300
},
301
{
302
label: 'Edit',
303
children: [
304
{
305
label: 'Undo',
306
shortcut: 'Ctrl+Z',
307
disabled: !canUndo.value,
308
onClick: undo
309
},
310
{
311
label: 'Redo',
312
shortcut: 'Ctrl+Y',
313
disabled: !canRedo.value,
314
onClick: redo
315
},
316
{ divided: true },
317
{
318
label: 'Cut',
319
shortcut: 'Ctrl+X',
320
disabled: !hasSelection.value,
321
onClick: cut
322
},
323
{
324
label: 'Copy',
325
shortcut: 'Ctrl+C',
326
disabled: !hasSelection.value,
327
onClick: copy
328
}
329
]
330
}
331
]
332
}));
333
</script>
334
```
335
336
### Menu Bar with Custom Styling
337
338
```vue
339
<template>
340
<menu-bar
341
:options="customMenuOptions"
342
class="custom-menu-bar"
343
>
344
<template #prefix>
345
<div class="brand-section">
346
<img src="/logo.svg" alt="Brand" class="brand-logo" />
347
<span class="brand-text">My App</span>
348
</div>
349
</template>
350
351
<template #suffix>
352
<div class="user-section">
353
<span class="user-name">{{ currentUser.name }}</span>
354
<button @click="showUserMenu" class="user-menu-btn">
355
<img :src="currentUser.avatar" alt="User" class="user-avatar" />
356
</button>
357
</div>
358
</template>
359
</menu-bar>
360
</template>
361
362
<style scoped>
363
.custom-menu-bar {
364
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
365
color: white;
366
padding: 0 16px;
367
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
368
}
369
370
.brand-section {
371
display: flex;
372
align-items: center;
373
gap: 8px;
374
}
375
376
.brand-logo {
377
width: 24px;
378
height: 24px;
379
}
380
381
.user-section {
382
display: flex;
383
align-items: center;
384
gap: 12px;
385
}
386
387
.user-avatar {
388
width: 32px;
389
height: 32px;
390
border-radius: 50%;
391
}
392
</style>
393
```
394
395
## Menu Bar Configuration
396
397
### MenuBarOptions Interface
398
399
Complete configuration interface extending MenuOptions with menu bar specific properties.
400
401
```typescript { .api }
402
interface MenuBarOptions extends Omit<MenuOptions, 'x'|'y'|'getContainer'> {
403
/** Whether the menu bar is in collapsed/mini mode */
404
mini?: boolean;
405
/** Popup direction for dropdown menus in collapsed state */
406
barPopDirection?: MenuPopDirection;
407
408
// Inherited from MenuOptions:
409
/** Array of top-level menu items */
410
items?: MenuItem[];
411
/** Menu theme */
412
theme?: string;
413
/** Z-index for dropdown menus */
414
zIndex?: number;
415
/** Custom CSS class */
416
customClass?: string;
417
/** Enable keyboard navigation */
418
keyboardControl?: boolean;
419
/** Maximum width for dropdown menus */
420
maxWidth?: number;
421
/** Maximum height for dropdown menus */
422
maxHeight?: number;
423
/** Minimum width for dropdown menus */
424
minWidth?: number;
425
/** Custom icon font class */
426
iconFontClass?: string;
427
/** Reserve icon width for items without icons */
428
preserveIconWidth?: boolean;
429
/** Menu close callback */
430
onClose?: (lastClickItem: MenuItem | undefined) => void;
431
/** Keyboard focus movement callbacks */
432
onKeyFocusMoveLeft?: () => void;
433
onKeyFocusMoveRight?: () => void;
434
}
435
```
436
437
### MenuBar Keyboard Navigation
438
439
The MenuBar component supports keyboard navigation when `keyboardControl` is enabled:
440
441
- **Arrow Left/Right**: Navigate between top-level menu items
442
- **Arrow Down**: Open dropdown menu
443
- **Arrow Up**: Close dropdown menu
444
- **Enter/Space**: Activate menu item
445
- **Escape**: Close all menus
446
447
```vue
448
<template>
449
<menu-bar :options="keyboardMenuOptions" />
450
</template>
451
452
<script setup>
453
const keyboardMenuOptions = {
454
keyboardControl: true,
455
items: [...],
456
onKeyFocusMoveLeft: () => {
457
// Handle left navigation
458
console.log('Focus moved left');
459
},
460
onKeyFocusMoveRight: () => {
461
// Handle right navigation
462
console.log('Focus moved right');
463
}
464
};
465
</script>
466
```