Context menus

A context menu contains a list of actions you can take related to some element in the workspace. A context menu is shown on right clicks and long presses.

The default context menu for a block

You may want to create a custom context menu option if you want to add a new kind of action the user can perform. For example, organizing all of the blocks in the workspace or downloading an image of the blocks. If you think the action will be used infrequently, the context menu is a great place to put it. Otherwise, you might want to create a more discoverable way to access the action.

Implement a new option

To implement a new context menu option, you need to fulfill the RegistryItem interface.

ID

The id property should be a unique string that indicates what your context menu option does.

const deleteOption = {
  id: 'deleteElement',
};

Scope

The scopeType property tells Blockly what context the menu option might be shown in and what information to pass to its displayText, preconditionFn, and callback. Context menus can be scoped to blocks, workspace comments, and workspaces.

const deleteOption = {
  scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
};

If you want your context menu to work in multiple scopes, you should duplicate the context menu option and redefine the scope parameter for each scope.

const otherDeleteOption = {...deleteOption};
otherDeleteOption.scopeType = Blockly.ContextMenuRegistry.ScopeType.COMMENT;

Display text

The displayText is what should be shown to the user as part of the menu option. The display text can be a string, or HTML, or a function that returns either a string or HTML.

const deleteOption = {
  displayText: 'Delete block',
};

If you want to display a translation from Blockly.Msg you need to use a function. If you try to assign the value directly, the messages may not be loaded and you'll get a value of undefined instead.

const deleteOption = {
  displayText: () => Blockly.Msg['MY_DELETE_OPTION_TEXT'],
};

If you use a function, it is also passed a Scope value which gives you access to the element the context menu is associated with (e.g. the block or workspace). You can use this to add information about the element to your display text.

const deleteOption = {
  displayText: (scope) => `Delete ${scope.block.type} block`,
}

Weight

The weight determines the order in which context menu items are displayed. More positive values are displayed lower in the list than less positive values. (You can imagine that options with higher weights are "heavier" so they sink to the bottom.)

const deleteOption = {
  weight: 10;
}

Weights for the built-in context menu options go in increasing order starting at 1 and increasing by 1.

Precondition

In addition to the scopeType, you can use the preconditionFn to restrict when and how a context menu option should be displayed.

It should return one of a set of strings: 'enabled', 'disabled', or 'hidden'.

Value Description Image
enabled Shows that the option is active. An enabled option
disabled Shows that the option is not active. A disabled option
hidden Hides the option.

The preconditionFn is also passed a Scope which you can use to determine the state of your option.

const deleteOption = {
  preconditionFn: (scope) => {
    if (scope.block.isDeletable()) {
      return 'enabled';
    }
    return 'disabled';
  }
}

Callback

The callback property performs the action of your context menu item. It is passed a Scope and a PointerEvent. The PointerEvent is the original event that triggered opening the context menu, not the one that selected an option. You can use the event to figure out where the click happened. This lets you, for example, create a new block at the click location.

const deleteOption = {
  callback: (scope, e) => {
    scope.block.dispose();
  }
}

Registration

To use your context menu option, you need to register it. You should do this once on page load. It can happen before or after you inject your workspace.

const deleteOption = { /* implementations from above */ };
Blockly.ContextMenuRegistry.registry.register(deleteOption);

Modify options per-block-type

Blocks have an additional way to modify context menus which is to use overwrite their customContextMenu property. This method takes in an array of ContextMenuOption objects (which are collated from the registered menu items) and then modifies that array in-place to determine the final set of displayed options.

For more information see Define blocks, custom context menus.

Workspaces also have a configureContextMenu method which works similarly.

Remove an option

You can remove an option from the context menu by unregistering it by ID.

Blockly.ContextMenuRegistry.registry.unregister('someID');

The IDs for the default options are in contextmenu_items.ts.

Modify an option

You can modify an existing option by getting the item from the registry and then modifying it in-place.

const option = Blockly.ContextMenuRegistry.registry.getItem('someID');
option?.displayText = 'some other display text';