Skip to content

Commit 706f5f0

Browse files
committed
Document "Menu Items" extension type for Umbraco: added new section in "Extension Types" with examples for manifest and TypeScript approaches, detailed usage, and custom implementations. Updated summary to include the new section.
1 parent a43d1ad commit 706f5f0

File tree

3 files changed

+273
-0
lines changed

3 files changed

+273
-0
lines changed

16/umbraco-cms/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
* [Kinds](customizing/extending-overview/extension-types/kind.md)
172172
* [Localization](customizing/extending-overview/extension-types/localization.md)
173173
* [Menu](customizing/extending-overview/extension-types/menu.md)
174+
* [Menu Items](customizing/extending-overview/extension-types/menu-item.md)
174175
* [Modals](customizing/extending-overview/extension-types/modals/README.md)
175176
* [Confirm Dialog](customizing/extending-overview/extension-types/modals/confirm-dialog.md)
176177
* [Custom Modals](customizing/extending-overview/extension-types/modals/custom-modals.md)

16/umbraco-cms/customizing/extending-overview/extension-types/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ The `localization` extension type is used to register additional languages and f
7373

7474
The `menu` extension type is used to create custom menus. These can be placed in sidebar extensions or displayed as a fly-out from a button, header, or workspace view.
7575

76+
### [Menu Items](menu-item.md)
77+
78+
The `menuItem` extension type is used to create custom menu items. These can be used in conjunction with custom menu extensions or placed in any of the existing/default Umbraco menus.
79+
7680
### [Modals](modals/README.md)
7781

7882
The `modal` extension type is used to configure and present dialogs and sidebars within the Umbraco backoffice.
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
---
2+
description: >-
3+
Create menu items that appear throughout the backoffice, in sidebars, button flyouts, and more.
4+
---
5+
6+
# Menu Items
7+
8+
Menu Item extensions are used in combination with [Menu](menu.md) extensions. Menu items can be placed in custom menus, sidebars, and even added into the built-in/default Umbraco menu extensions. Extension authors can use the default Menu Item component or create their own custom Menu Items and register them as extensions.
9+
10+
<figure><img src="../../../.gitbook/assets/menu-item.png" alt="" width="250"><figcaption><p>Menu Item</p></figcaption></figure>
11+
12+
Menu Item extensions can be defined using either JSON in `umbraco-package.json` or using TypeScript.
13+
14+
## Creating Menu Items
15+
16+
Menu Item extensions can be created using either JSON or TypeScript. Both approaches are shown below.
17+
18+
### Manifest
19+
20+
To add custom menu items, you can define a single MenuItem manifest and link an element to it. In this element, you can fetch the data and render as many menu items as you want based on that data.
21+
22+
{% tabs %}
23+
{% tab title="JSON" %}
24+
{% code title="umbraco-package.json" %}
25+
```json
26+
{
27+
"$schema": "../../umbraco-package-schema.json",
28+
"name": "My Package",
29+
"version": "0.1.0",
30+
"extensions": [
31+
{
32+
"type": "menuItem",
33+
"alias": "My.MenuItem",
34+
"name": "My Menu Item",
35+
"element": "./menu-items.ts",
36+
"meta": {
37+
"label": "My Menu Item",
38+
"menus": ["My.Menu"]
39+
}
40+
}
41+
]
42+
}
43+
```
44+
{% hint style="info" %}
45+
The `element` parameter is optional. Omitting it will render a menu item styled using Umbraco defaults.
46+
{% endhint %}
47+
{% endcode %}
48+
{% endtab %}
49+
{% tab title="TypeScript" %}
50+
51+
Extension authors define the menu manifest, then register it dynamically/during runtime using a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension.
52+
53+
The `element` attribute will point toward a custom Lit component, an example of which will be in the next section of this article.
54+
55+
{% code title="my-menu/manifests.ts" %}
56+
```typescript
57+
import type { ManifestMenuItem } from '@umbraco-cms/backoffice/menu';
58+
59+
export const menuItemManifest: ManifestMenuItem = {
60+
type: 'menuItem',
61+
alias: 'My.MenuItem',
62+
name: 'My Menu Item',
63+
meta: {
64+
label: 'My Menu Item',
65+
menus: ["My.Menu"]
66+
},
67+
};
68+
```
69+
{% endcode %}
70+
71+
{% code title="entrypoints/entrypoints.ts" %}
72+
```typescript
73+
import type {
74+
UmbEntryPointOnInit,
75+
} from "@umbraco-cms/backoffice/extension-api";
76+
import { umbExtensionsRegistry } from "@umbraco-cms/backoffice/extension-registry";
77+
import { menuItemManifest } from "./../my-menu/manifests.ts";
78+
79+
export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => {
80+
console.log("Hello from my extension 🎉");
81+
82+
umbExtensionsRegistry.register(menuItemManifest);
83+
};
84+
```
85+
{% endcode %}
86+
{% endtab %}
87+
{% endtabs %}
88+
89+
## Custom menu items
90+
91+
{% hint style="info" %}
92+
**Note:** Displaying menu item extensions does not require extension authors to create custom menu item subclasss. This step is optional.
93+
{% endhint %}
94+
95+
To render your menu items in Umbraco, extension authors can use the [Umbraco UI Menu Item component](https://uui.umbraco.com/?path=/docs/uui-menu-item--docs). This component enables nested menu structures with a few lines of markup.
96+
97+
`<uui-menu-item>` nodes accept the `has-children` boolean attribute, which will display a caret icon indicating nested items. Tying this boolean attribute to a variable requires using the `?` Lit directive, which would look similar to this: `?has-children=${boolVariable}`.
98+
99+
```html
100+
<uui-menu-item label="Menu Item 1" has-children>
101+
<uui-menu-item label="Nested Menu Item 1"></uui-menu-item>
102+
<uui-menu-item label="Nested Menu Item 2"></uui-menu-item>
103+
</uui-menu-item>
104+
```
105+
106+
### Custom menu item element example
107+
108+
Custom elements can fetch the data and render menu items using markup, like above. Storing the results of the fetch in a `@state()` variable will trigger a re-render of the component when the value of the variable changes.
109+
110+
{% tabs %}
111+
{% tab title="my-menu/menu-items.ts" %}
112+
{% code title="menu-items.ts" overflow="wrap" lineNumbers="true" %}
113+
```typescript
114+
import type { UmbMenuItemElement } from '@umbraco-cms/backoffice/menu';
115+
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
116+
import { html, TemplateResult, customElement, state } from '@umbraco-cms/backoffice/external/lit';
117+
import { MyMenuItemResponseModel, MyMenuResource } from '../../../api';
118+
119+
const elementName = 'my-menu-item';
120+
121+
@customElement(elementName)
122+
class MyMenuItems extends UmbLitElement implements UmbMenuItemElement {
123+
@state()
124+
private _items: MyMenuItemResponseModel[] = []; // Store fetched items
125+
126+
@state()
127+
private _loading: boolean = true; // Track loading state
128+
129+
@state()
130+
private _error: string | null = null; // Track any errors
131+
132+
override firstUpdated() {
133+
this.fetchInitialItems(); // Start fetching on component load
134+
}
135+
136+
// Fetch initial items
137+
async fetchInitialItems() {
138+
try {
139+
this._loading = true;
140+
this._items = ((await MyMenuResource.getMenuApiV1()).items); // Fetch root-level items
141+
} catch (e) {
142+
this._error = 'Error fetching items';
143+
} finally {
144+
this._loading = false;
145+
}
146+
}
147+
148+
// Render items
149+
renderItems(items: MyMenuItemResponseModel[]): TemplateResult {
150+
return html`
151+
${items.map(element => html`
152+
<uui-menu-item label="${element.name}" ?has-children=${element.hasChildren}>
153+
${element.type === 1
154+
? html`<uui-icon slot="icon" name="icon-folder"></uui-icon>`
155+
: html`<uui-icon slot="icon" name="icon-autofill"></uui-icon>`}
156+
<!-- recursively render children -->
157+
${element.hasChildren ? this.renderItems(element.children) : ''}
158+
</uui-menu-item>
159+
`)}
160+
`;
161+
}
162+
163+
// Main render function
164+
override render() {
165+
if (this._loading) {
166+
return html`<uui-loader></uui-loader>`;
167+
}
168+
169+
if (this._error) {
170+
return html`<uui-menu-item active disabled label="Could not load form tree!">
171+
</uui-menu-item>`;
172+
}
173+
174+
// Render items if loading is done and no error occurred
175+
return this.renderItems(this._items);
176+
}
177+
}
178+
179+
export { MyMenuItems as element };
180+
181+
declare global {
182+
interface HTMLElementTagNameMap {
183+
[elementName]: MyMenuItems;
184+
}
185+
}
186+
```
187+
{% endcode %}
188+
{% endtab %}
189+
190+
{% tab title="my-menu/manifests.ts" %}
191+
```typescript
192+
import type { ManifestMenuItem } from "@umbraco-cms/backoffice/menu";
193+
194+
export const MyMenuItemManifest: ManifestMenuItem = {
195+
type: "menuItem",
196+
kind: "tree",
197+
alias: "MyMenuItem.CustomMenu?Item",
198+
name: "My Menu Item Custom Menu Item",
199+
element: () => import("./menu-items.ts"),
200+
meta: {
201+
label: "Smtp",
202+
menus: ["Umb.Menu.Content"],
203+
},
204+
};
205+
```
206+
{% hint style="info" %}
207+
**Note:** Extension authors can use the `kind` property to define the type of menu item. The `kind` property can be set to `tree` or `list`.
208+
{% endhint %}
209+
{% endtab %}
210+
211+
{% tab title="entrypoints/entrypoints.ts" %}
212+
```typescript
213+
import type {
214+
UmbEntryPointOnInit,
215+
} from "@umbraco-cms/backoffice/extension-api";
216+
import { umbExtensionsRegistry } from "@umbraco-cms/backoffice/extension-registry";
217+
import { MyMenuItemManifest } from "./../my-menu/manifests.ts";
218+
219+
export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => {
220+
console.log("Hello from my extension 🎉");
221+
222+
umbExtensionsRegistry.register(MyMenuItemManifest);
223+
};
224+
```
225+
{% endtab %}
226+
{% endtabs %}
227+
228+
## Adding menu items to an existing menu
229+
230+
Extension authors are able to add their own additional menu items to the menus that ship with Umbraco.
231+
232+
Some examples of these built-in menus include:
233+
234+
* Content - `Umb.Menu.Content`
235+
* Media - `Umb.Menu.Media`
236+
* Settings - `Umb.Menu.StructureSettings`
237+
* Templating - `Umb.Menu.Templating`
238+
* ...
239+
240+
Additional Umbraco menus (nine, total) can be found using the Extension Insights browser and selecting **Menu** from the dropdown.
241+
242+
<figure><img src="../../../.gitbook/assets/extension-types-backoffice-browser.png" alt=""><figcaption><p>Backoffice extension browser</p></figcaption></figure>
243+
244+
### Extending Menus
245+
246+
To add a menu item to an existing menu, use the `meta.menus` property.
247+
248+
{% code title="umbraco-package.json" %}
249+
```json
250+
{
251+
"$schema": "../../umbraco-package-schema.json",
252+
"name": "My Package",
253+
"version": "0.1.0",
254+
"extensions": [
255+
{
256+
"type": "menuItem",
257+
"alias": "My.MenuItem",
258+
"name": "My Menu Item",
259+
"meta": {
260+
"label": "My Menu Item",
261+
"menus": ["Umb.Menu.Content"]
262+
},
263+
"element": "menu-items.js"
264+
}
265+
]
266+
}
267+
```
268+
{% endcode %}

0 commit comments

Comments
 (0)