0
# Menus
1
2
Theia's menu system provides hierarchical menu management with dynamic contributions, context menus, and command integration for building comprehensive application interfaces.
3
4
## Capabilities
5
6
### Menu Model Registry
7
8
Central registry for menu structure and menu items.
9
10
```typescript { .api }
11
/**
12
* Registry for menu models and actions
13
*/
14
interface MenuModelRegistry {
15
/**
16
* Register menu action
17
* @param menuPath - Path to menu location
18
* @param item - Menu action to register
19
* @returns Disposable to unregister
20
*/
21
registerMenuAction(menuPath: MenuPath, item: MenuAction): Disposable;
22
23
/**
24
* Register submenu
25
* @param menuPath - Path to parent menu
26
* @param label - Submenu label
27
* @returns Menu path for the new submenu
28
*/
29
registerSubmenu(menuPath: MenuPath, label: string): MenuPath;
30
31
/**
32
* Get menu model for path
33
* @param menuPath - Menu path
34
* @returns Menu model
35
*/
36
getMenu(menuPath: MenuPath): CompositeMenuNode;
37
38
/**
39
* Get all menu paths
40
* @returns Array of menu paths
41
*/
42
getMenuPaths(): MenuPath[];
43
}
44
45
/**
46
* Service token for MenuModelRegistry
47
*/
48
const MenuModelRegistry: symbol;
49
```
50
51
### Menu Paths
52
53
Hierarchical menu location identifiers.
54
55
```typescript { .api }
56
/**
57
* Menu path array for identifying menu locations
58
*/
59
type MenuPath = string[];
60
61
/**
62
* Common menu paths
63
*/
64
namespace MenuPaths {
65
/** File menu */
66
const File: MenuPath;
67
68
/** Edit menu */
69
const Edit: MenuPath;
70
71
/** View menu */
72
const View: MenuPath;
73
74
/** Help menu */
75
const Help: MenuPath;
76
}
77
```
78
79
### Menu Actions
80
81
Individual menu items that execute commands.
82
83
```typescript { .api }
84
/**
85
* Menu action definition
86
*/
87
interface MenuAction {
88
/** Command to execute */
89
commandId: string;
90
91
/** Display label (overrides command label) */
92
label?: string;
93
94
/** Icon CSS class */
95
icon?: string;
96
97
/** Menu item order/priority */
98
order?: string;
99
100
/** Alt text for accessibility */
101
alt?: string;
102
103
/** When clause for conditional display */
104
when?: string;
105
106
/** Group for menu organization */
107
group?: string;
108
}
109
```
110
111
**Usage Example:**
112
113
```typescript
114
import { injectable, inject } from "@theia/core";
115
import { MenuModelRegistry, MenuAction } from "@theia/core/lib/common";
116
117
@injectable()
118
export class MyMenuContribution {
119
constructor(
120
@inject(MenuModelRegistry)
121
private readonly menus: MenuModelRegistry
122
) {}
123
124
registerMenus(): void {
125
// Register action in File menu
126
const openAction: MenuAction = {
127
commandId: 'my-extension.open-file',
128
label: 'Open Special File',
129
icon: 'fa fa-file-o',
130
order: '1',
131
group: 'file'
132
};
133
134
this.menus.registerMenuAction(['file'], openAction);
135
136
// Create submenu
137
const mySubmenu = this.menus.registerSubmenu(['view'], 'My Extension');
138
139
// Add actions to submenu
140
this.menus.registerMenuAction(mySubmenu, {
141
commandId: 'my-extension.show-panel',
142
label: 'Show Panel',
143
order: '1'
144
});
145
146
this.menus.registerMenuAction(mySubmenu, {
147
commandId: 'my-extension.settings',
148
label: 'Settings',
149
order: '2'
150
});
151
}
152
}
153
```
154
155
### Menu Nodes
156
157
Menu structure representation.
158
159
```typescript { .api }
160
/**
161
* Base menu node interface
162
*/
163
interface MenuNode {
164
/** Node identifier */
165
readonly id: string;
166
167
/** Display label */
168
readonly label?: string;
169
170
/** Icon CSS class */
171
readonly icon?: string;
172
173
/** Sort string for ordering */
174
readonly sortString?: string;
175
176
/** When clause for visibility */
177
readonly when?: string;
178
}
179
180
/**
181
* Composite menu node containing child nodes
182
*/
183
interface CompositeMenuNode extends MenuNode {
184
/** Child menu nodes */
185
readonly children: MenuNode[];
186
187
/** True if node has children */
188
readonly hasChildren: boolean;
189
}
190
191
/**
192
* Action menu node that executes commands
193
*/
194
interface ActionMenuNode extends MenuNode {
195
/** Command to execute */
196
readonly command: string;
197
198
/** Command arguments */
199
readonly args?: any[];
200
201
/** Alt text */
202
readonly alt?: string;
203
}
204
```
205
206
### Context Menus
207
208
Dynamic context menus for widgets and UI elements.
209
210
```typescript { .api }
211
/**
212
* Context menu renderer interface
213
*/
214
interface ContextMenuRenderer {
215
/**
216
* Render context menu
217
* @param menuPath - Menu path
218
* @param anchor - Anchor element or coordinates
219
* @param onHide - Callback when menu hides
220
*/
221
render(
222
menuPath: MenuPath,
223
anchor: Element | { x: number; y: number },
224
onHide?: () => void
225
): Promise<void>;
226
}
227
228
/**
229
* Service token for ContextMenuRenderer
230
*/
231
const ContextMenuRenderer: symbol;
232
```
233
234
**Usage Example:**
235
236
```typescript
237
import { inject, injectable } from "@theia/core";
238
import { ContextMenuRenderer } from "@theia/core/lib/browser";
239
240
@injectable()
241
export class MyWidget {
242
constructor(
243
@inject(ContextMenuRenderer)
244
private readonly contextMenuRenderer: ContextMenuRenderer
245
) {}
246
247
private handleContextMenu(event: MouseEvent): void {
248
event.preventDefault();
249
250
// Render context menu at mouse position
251
this.contextMenuRenderer.render(
252
['my-widget-context'],
253
{ x: event.clientX, y: event.clientY }
254
);
255
}
256
257
private setupContextMenu(): void {
258
// Register context menu items
259
this.menus.registerMenuAction(['my-widget-context'], {
260
commandId: 'my-widget.copy',
261
label: 'Copy',
262
order: '1'
263
});
264
265
this.menus.registerMenuAction(['my-widget-context'], {
266
commandId: 'my-widget.paste',
267
label: 'Paste',
268
order: '2'
269
});
270
}
271
}
272
```
273
274
### Menu Contribution
275
276
Extension point for contributing menus.
277
278
```typescript { .api }
279
/**
280
* Menu contribution interface
281
*/
282
interface MenuContribution {
283
/**
284
* Register menus
285
* @param menus - Menu model registry
286
*/
287
registerMenus(menus: MenuModelRegistry): void;
288
}
289
290
/**
291
* Service token for MenuContribution
292
*/
293
const MenuContribution: symbol;
294
```
295
296
## Advanced Features
297
298
### Conditional Menus
299
300
Menus that appear based on context conditions.
301
302
```typescript
303
// Register conditional menu action
304
this.menus.registerMenuAction(['edit'], {
305
commandId: 'editor.action.rename',
306
label: 'Rename Symbol',
307
when: 'editorHasRenameProvider && editorTextFocus'
308
});
309
```
310
311
### Menu Groups
312
313
Organize menu items into logical groups with separators.
314
315
```typescript
316
// Actions in same group appear together
317
this.menus.registerMenuAction(['file'], {
318
commandId: 'file.new',
319
group: 'new',
320
order: '1'
321
});
322
323
this.menus.registerMenuAction(['file'], {
324
commandId: 'file.open',
325
group: 'new',
326
order: '2'
327
});
328
329
// Different group creates separator
330
this.menus.registerMenuAction(['file'], {
331
commandId: 'file.save',
332
group: 'save',
333
order: '1'
334
});
335
```
336
337
## Types
338
339
```typescript { .api }
340
/**
341
* Menu-related type definitions
342
*/
343
type MenuItemRole = 'normal' | 'separator' | 'submenu';
344
345
interface MenuOptions {
346
role?: MenuItemRole;
347
type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio';
348
checked?: boolean;
349
enabled?: boolean;
350
visible?: boolean;
351
}
352
353
type MenuCallback = () => void;
354
```