Skip to main content

Actions

Experimental

The current implementation of the action system is experimental and is likely to undergo significant revisions to meet the performance demands of real-world applications with thousands of actions.

An action represents an available functionality, without specifying how it's invoked. Shortcuts can separately be assigned to actions via a keymap, allowing for a customizable and personalized user experience. The action system, at its core, is only about defining actions for each part of the UI and associating these actions with shortcuts, without any direct dependencies on other aspects of the design system. However, there are UI components available to facilitate creation of toolbars and menus based on actions.

note

The core functionality of the action system may be extracted into a standalone package in the future, making it a reusable component for applications built using any design system.

The action system consists of the following primary components:

  • ActionsProvider component, which allows for defining actions for a UI area.
  • KeymapProvider component, which allows for assigning shortcut(s) to actions.
  • UI components that helps with creating menus, toolbars, etc. based on action system abstractions.

Below is a basic example of how these components are used. Subsequent sections will provide detailed explanations of the components and interfaces involved.

Result
Loading...
Live Editor

Defining actions

ActionsProvider is used as a wrapper component that defines available actions for the wrapped UI. Multiple, potentially nested ActionsProvider may be rendered in an application. ActionProvider itself doesn't render any wrapper element. Shortcut event handler props are passed to children which is expected to be a render function:

<ActionsProvider actions={actions}>
{({ shortcutHandlerProps }) => <div {...shortcutHandlerProps}>...</div>}
</ActionsProvider>

actions is an array of objects implementing ActionDefinition interface. At minimum, an action must have:

  • id: A unique identifier based on which shortcuts are assigned in keymap.
  • actionPerformed: A function to be invoked when the action is triggered, e.g. via a shortcut.
  • title: The only mandatory presentation information for the action.

Moreover, an action has the following optional properties:

  • isDisabled: If true, prevents action from being performed. Action UI components will also utilize this field to either disable or hide the corresponding UI component.
  • icon: A React node to be used as the associated icon for the action. It's required if the action is to be rendered as an ActionButton, and optional for menu items.
  • description: Plain text, additional description about the action. Not used in ActionButton, or menu items.

Action Groups

An ActionGroup is a special type of action with a list of children actions. An action group itself can be performed.

Default action group

A default implementation of action group is available, which when performed, opens a Popup, presenting the children actions in a SpeedSearchMenu. The default action group requires PopupManager, for opening the popup.

useCreateDefaultActionGroup returns a function that creates action groups:

import { useCreateDefaultActionGroup } from "@intellij-platform/core";

const createDefaultActionGroup = useCreateDefaultActionGroup();

createDefaultActionGroup({
id: "MY_ACTION_GROUP",
title: "My Action Group",
children: [
/* action definitions */
],
});
Result
Loading...
Live Editor

Using actions

useActions can be used to query the list of all provided actions. Use useAction instead to query an specific action, by id. The queried Action object has a perform method which can be invoked e.g. when a menu item or a button is pressed. Note that Action interface is quite similar but not identical to ActionDefinition.

function MyActionButton() {
const action = useAction("MY_ACTION");
return action && <Button onPress={() => action.perform()}>My Action</Button>;
}

useActionGroup is also similar to useAction, but it asserts the queried action is a group.

Query actions based on DOM elements

useAction or useActions is the canonical API for accessing currently provided actions from a React component. getAvailableActionsFor is an alternative API that allows for querying available actions from a DOM element. This can be useful in specific scenarios such as the implementation of the find action. You can also check out the implementation of "find action" action in the example app.

UI components

useAction, and useActionGroup can be used to query actions and create a menu or toolbar out of them. For typical use cases, however, there are convenient components that interface on Action or action id.

Use ActionsMenu to render a list of action objects as a menu. ActionGroup items are rendered as a section or a submenu, depending on menuPresentation property of the action group object. Note that ActionsMenu just provides an interface based on action items, but it doesn't query any action from the actions context, and just uses action properties to create menu items from it.

Result
Loading...
Live Editor

Use ActionGroupMenu to render actions of an action group, as a menu:

Result
Loading...
Live Editor

ActionButton

Use ActionButton to create an IconButton based on a provided action. Unlike ActionsMenu and ActionGroupMenu, ActionButton interfaces on action ID, and queries the target action via useAction. If the action doesn't exist, it renders nothing.

Result
Loading...
Live Editor

Shortcuts and key mapping

A Keymap is a mapping from action ids to a list of associated shortcuts. In an application that uses actions, the KeymapProvider is typically used as a top level wrapper, to provide a keymap.

import {Keymap, KeymapProvider} from '@intellij-platform/core';

const keymap: Keymap = isMac() ? macKeymap : defaultKeymap;
<KeymapProvider keymap={keymap}>...</KeyMapProvider>

Differences with the Intellij Platform

While the action system almost replicates Intellij Platform's Action System, there are some design differences worth noting:

TODO