Menus in the Extensibiity API

Last modified: December 4, 2025

A menu has the following properties:

Property Description
caption The text of the menu item
menuId A unique identifier for the menu item
subMenus A list of sub-menu items
hasSeparatorBefore
(default: false)
Adds a visual separator before the item
hasSeparatorAfter
(default: false)
Adds a visual separator after the item
enabled
(default: true)
If disabled, the action of the menu will not be invoked when clicked
action The action that executes when the menu is clicked

A menu can either have a context or no context. When adding a context menu to a document or an entity through the appExplorer or documents APIs, Studio Pro sends the document Id back to the menu. The menu then invokes the action and passes this document Id as the argument. Because of this, the menu must be identified as Menu<DocumentContext>. When you create the menu with this context, the action needs to have a DocumentContext argument; otherwise, the action will not receive the document Id when the context menu is clicked.

The DocumentContext type has only one property, the documentId string:

type DocumentContext = { documentId: string };

Below are the different ways to use menus:

import { DocumentContext, IComponent, Menu, getStudioProApi } from "@mendix/extensions-api";

export const component: IComponent = {
    async loaded(componentContext) {
        const studioPro = getStudioProApi(componentContext);
        const menuApi = studioPro.ui.extensionsMenu;
        const appExplorerApi = studioPro.ui.appExplorer;
        const messageBoxApi = studioPro.ui.messageBoxes;

        const menuId = "menu-without-context";

        const menu: Menu = {
            caption: "Menu Without Context",
            menuId,
            action: async () => await messageBoxApi.show("info", `My menu '${menuId}' was clicked`)
        };

        await menuApi.add(menu);

        const documentContextMenuId = "menu-with-context";

        const documentContextMenu: Menu<DocumentContext> = {
            caption: "Menu With Context",
            menuId: documentContextMenuId,
            action: async (arg: DocumentContext) =>
                await messageBoxApi.show("info", `My menu '${documentContextMenuId}' for microflow id ${arg.documentId} was clicked`)
        };

        await appExplorerApi.addContextMenu(documentContextMenu, "Microflows$Microflow");

        const documentContextMenuWithoutPayloadId = "menu-with-context-no-payload";

        const documentContextMenuNoPayload: Menu<DocumentContext> = {
            caption: "Menu With Context But No Payload",
            menuId: documentContextMenuWithoutPayloadId,
            action: async () =>
                await messageBoxApi.show("info", `My menu '${documentContextMenuWithoutPayloadId}' for a microflow was clicked`)
        };

        await appExplorerApi.addContextMenu(documentContextMenuNoPayload, "Microflows$Microflow");
    }
};