Custom Action Management

🚧

Important!

Custom actions are only supported for non-public apps that will be distributed privately via a shareable authorization link from your App Settings page. This means that apps built with custom actions will not be eligible for distribution via the Miro Marketplace at this time, and cannot be widely and publicly distributed. Please follow our Changelog for further developments.

Methods

register(...)

(customAction: CustomAction<T>) => Promise<CustomAction<T>>
🚦 Rate limit: Level 1

Experimental feature Experimental

You use this method to register a custom action with an app.
The method takes a single argument: an object that defines the custom action.

You need to register custom actions in the headless iframe of your app so that the actions are available as long as the app is running on the board.
For Miro apps, this is usually the index.js/.ts file.
If you register a custom action in the panel or the modal iframe, the operation throws an error.

Custom actions registration requires two steps:

  1. Subscribe to the event dispatched by the custom action using miro.board.ui.on method
  2. Register custom action with it's definition. Apps cannot register custom actions that don't have subscription.
await miro.board.ui.on('custom:translate-content', handler);
await miro.board.experimental.action.register(
  {
    "event": "translate-content",
    "ui": {
      "label":
        "en": "Translate content",
      "icon": "chat-two",
      "description": "Translate the content of the board items included in the current selection.",
    },
    "scope": "local",
    "predicate": {
      "type": "text"
    },
    "contexts": {
        "item": {}
    }
  }
);

You can learn more about custom action on our tutorial.


deregister(...)

(eventName: string) => Promise<void>
🚦 Rate limit: Level 1

Experimental feature Experimental

Use this method to deregister a custom action that was previously registered by an app.

The method takes one argument:

  • The name of the event used when registering the custom action.
await miro.board.ui.on('custom:translate-content', handler);
await miro.board.experimental.action.register(
  {
    "event": "translate-content",
    "ui": {
      "label":
        "en": "Translate content",
      "icon": "chat-two",
      "description": "Translate the content of the board items included in the current selection.",
    },
    "scope": "local",
    "predicate": {
      "type": "text"
    },
    "contexts": {
        "item": {}
    }
  }
);

await miro.board.experimental.action.deregister("translate-content")

Type definitions

CustomActionFilter
{
  $and?: Array<CustomActionFilter<T>>
  $eq?: T
  $exists?: boolean
  $gt?: T
  $gte?: T
  $in?: Array<T>
  $lt?: T
  $lte?: T
  $ne?: T
  $nin?: Array<T>
  $not?: CustomActionFilter<T>
  $or?: Array<CustomActionFilter<T>>
  $regex?: string
  $where?: string
}
CustomActionPredicate
CustomActionPredicate:
  | { $and?: Array<CustomActionPredicate<T>>; $not?: CustomActionPredicate<T>; $or?: Array<CustomActionPredicate<T>> }
  | CustomActionFilter<T>
  | {}
  | {}
CustomAction
{
  contexts?: { item?: {} }
  event: string
  predicate?: CustomActionPredicate<ItemsProps<T>>
  scope?: 'local' | 'global'
  selection?: 'single' | 'multi'
  title="ui">ui?: {
    description?: string | Partial<Record<SupportedLanguages, string>>
    icon: string
    label: string | Partial<Record<SupportedLanguages, string>>
    position?: number
  }
}
contexts

contexts specifies where within the board UI the custom action will be accessible to users. It establishes the entry point for the custom action, indicating the UI element users can interact with to execute the custom action.

Currently, custom actions are available only in the context menu of selected board items.

Therefore, item is the only supported property for contexts at the moment.
The value of contexts.item is an empty object for now. Default value: {}.

"contexts": {
  "item": {}
}

Makes the custom action available in a specific context on the board.
Currently, you can only make custom actions available in the context menu of selected board items, Tag cannot be used as an item.

event

The name of the custom event to which the app subscribes in order to respond with a custom action. The event name must match the value of the ${string} placeholder in the custom:${string} event name you provide to the on property when subscribing to the app.

  • The event name can contain only lowercase alphabetic characters and hyphens (^[a-z]+(-[a-z]+)\*$).
  • It cannot contain spaces.
  • It cannot exceed 30 characters.

Example:

// Event name
const eventName = 'translate-content';

// Custom event name that the app subscribes to.
await miro.board.ui.on(`custom:${eventName}`, handler);
predicate

The predicate property specifies the criteria that determine which board items a custom action applies to.

The custom action only appears in the context menu when all currently selected items match the conditions defined in predicate.

predicate evaluates each selected item individually, even with multi-selections. It checks each item separately and must return true for every item in the selection.

If any selected item fails the predicate check, the custom action does not display.

In summary, predicate allows you to selectively show custom actions based on rules that apply to the current selection. The action only appears when all selected items pass the predicate criteria.

  • The conditions that you can set with predicate correspond to the supported board item properties.
  • predicate syntax leverages the MongoDB query DSL syntax.
    This approach offers a wide range of operators that allow granular control of the availability of a custom action on the board UI.
// Example of a predicate that makes a custom action available only when
// the selected board items are shapes, texts, or sticky notes.
"predicate": {
  "type": {
    "$in": ["shape", "text", "sticky_note"]
  },
}
scope

scope defines the scope of the custom action and how it interacts with other capabilities in the board. As of now, this property is not actually relevant since we only support local scope for the time being. Default value: local.

selection

selection determines whether the custom action is displayed for single or multiple selected items. Use multi if you want the custom action to be displayed when the selection includes 1 or more items and they all match the predicate. Use single for the custom action to be shown when there is only one selected item and it matches the predicate. Default value: multi.

ui

The object exposes content that is displayed to board users in the context menu when one or more board items are selected.


All properties

PropertyType
deregister(...)
(eventName: string) => Promise<void>
register(...)
(customAction: CustomAction<T>) => Promise<CustomAction<T>>