---
title: "Context-sensitive menus"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:context-menu@main"
source: "ApiOverview/Backend/ContextualMenu.rst"
modified: "2026-09-15T12:49:12+00:00"
---

# Context-sensitive menus

Contextual menus exist in many places in the TYPO3 backend. Just try your
luck clicking on any **icon** that you see. Chances are good that a contextual
menu will appear, offering useful functions to execute.

![The context menu now contains an additional item "Hello World"](../../Images/ManualScreenshots/Examples/ContextualMenuExtended/ContextMenuTtContent.png)

## Context menu rendering flow

### Markup

The context menu is shown after clicking on the HTML element which has the
`data-contextmenu-trigger` attribute set together with
`data-contextmenu-table`, `data-contextmenu-uid` and optional
`data-contextmenu-context` attributes.

The HTML attribute `data-contextmenu-trigger` has the following options:

-   `click`: Opens the context menu on the "click" and "contextmenu"
    events
-   `contextmenu`: Opens the context menu only on the "contextmenu" event

The JavaScript click event handler is implemented in the
[ES6 module](https://docs.typo3.org/permalink/t3coreapi:backend-javascript-es6@main) `@typo3/backend/context-menu.js`. It takes the
data attributes mentioned above and executes an Ajax call to the
`\TYPO3\CMS\Backend\Controller\ContextMenuController->getContextMenuAction()`.

### `ContextMenuController`

`ContextMenuController` asks `\TYPO3\CMS\Backend\ContextMenu\ContextMenu`
to generate an array of items. `ContextMenu` builds a list of available
item providers by asking each whether it can provide items
(`$provider->canHandle()`), and what priority it has
(`$provider->getPriority()`).

#### Item providers registration

Custom item providers must implement
`\TYPO3\CMS\Backend\ContextMenu\ItemProviders\ProviderInterface` and can
extend `\TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider`.

They are then automatically registered by adding the `backend.contextmenu.itemprovider`
tag, if `autoconfigure` is enabled in `Services.yaml`. The class
`\TYPO3\CMS\Backend\ContextMenu\ItemProviders\ItemProvidersRegistry` then
automatically receives those services and registers them.

If `autoconfigure` is
not enabled in your `Configuration/Services.(yaml|php)` file,
manually configure your item providers with the
`backend.contextmenu.itemprovider` tag.

There are two item providers which are always available:

-   `\TYPO3\CMS\Backend\ContextMenu\ItemProviders\PageProvider`
-   `\TYPO3\CMS\Backend\ContextMenu\ItemProviders\RecordProvider`

#### Gathering items

A list of providers is sorted by priority, and then each provider is asked to
add items. The generated array of items is passed from an item provider with
higher priority to a provider with lower priority.

After that, a compiled list of items is returned to the
`ContextMenuController` which passes it back to the
`ContextMenu.js` as JSON.

### Menu rendering in JavaScript

Based on the JSON data `context-menu.js` is rendering a context menu. If
one of the items is clicked, the according JavaScript `callbackAction` is
executed on the [ES6 module](https://docs.typo3.org/permalink/t3coreapi:backend-javascript-es6@main) `@typo3/backend/context-menu-actions.js`
or other modules defined in the JSON as `additionalAttributes['data-callback-module']`.

Example of the JSON response:

**Example of the JSON response**

```javascript
{
   "view":{
      "type":"item",
      "label":"Show",
      "icon":"<span class=\"t3js-icon icon icon-size-small icon-state-default icon-actions-document-view\" data-identifier=\"actions-document-view\">\n\t<span class=\"icon-markup\">\n<img src=\"\/typo3\/sysext\/core\/Resources\/Public\/Icons\/T3Icons\/actions\/actions-document-view.svg\" width=\"16\" height=\"16\" \/>\n\t<\/span>\n\t\n<\/span>",
      "additionalAttributes":{
         "data-preview-url":"http:\/\/typo37.local\/index.php?id=47"
      },
      "callbackAction":"viewRecord"
   },
   "edit":{
      "type":"item",
      "label":"Edit",
      "icon":"",
      "additionalAttributes":[
      ],
      "callbackAction":"editRecord"
   },
   "divider1":{
      "type":"divider",
      "label":"",
      "icon":"",
      "additionalAttributes":[

      ],
      "callbackAction":""
   },
   "more":{
      "type":"submenu",
      "label":"More options...",
      "icon":"",
      "additionalAttributes":[

      ],
      "callbackAction":"openSubmenu",
      "childItems":{
         "newWizard":{
            "type":"item",
            "label":"'Create New' wizard",
            "icon":"",
            "additionalAttributes":{
            },
            "callbackAction":"newContentWizard"
         }
      }
   }
}
```

## API usage in the Core

Several TYPO3 Core modules are already using this API for adding or modifying
items. See following places for a reference:

-   EXT:impexp module adds import and export options for pages, content elements
    and other records. See item provider
    `\TYPO3\CMS\Impexp\ContextMenu\ItemProvider` and [ES6 module](https://docs.typo3.org/permalink/t3coreapi:backend-javascript-es6@main)
    `@typo3/impexp/context-menu-actions.js`.
-   EXT:filelist module provides several item providers for files, folders,
    file mounts, filestorage, and drag-drop context menu for the folder tree.
    See following item providers:
    `\TYPO3\CMS\Filelist\ContextMenu\ItemProviders\FileDragProvider`,
    `\TYPO3\CMS\Filelist\ContextMenu\ItemProviders\FileProvider`,
    `\TYPO3\CMS\Filelist\ContextMenu\ItemProviders\FileStorageProvider`,
    `\TYPO3\CMS\Filelist\ContextMenu\ItemProviders\FilemountsProvider`
    and the [ES6 module](https://docs.typo3.org/permalink/t3coreapi:backend-javascript-es6@main) `@typo3/filelist/context-menu-actions.js`

## Adding context menu to elements in your backend module

Enabling context menu in your own backend modules is quite straightforward.
The examples below are taken from the "beuser" system extension and
assume that the module is Extbase-based.

The first step is to include the needed JavaScript using the
`includeJavaScriptModules` property
of the standard backend container Fluid view helper (or backend page
renderer view helper).

Doing so in your layout is sufficient (see
`typo3/sysext/beuser/Resources/Private/Layouts/Default.fluid.html`).

**EXT:my_extension/Resources/Private/Templates/SomeTemplate.fluid.html**

```html
<!-- TYPO3 v12 and above -->
<f:be.pageRenderer includeJavaScriptModules="{0: '@typo3/backend/context-menu.js'}">
    // ...
</f:be.pageRenderer>

```

The second step is to activate the context menu on the icons. This kind of markup
is required (taken from
`typo3/sysext/beuser/Resources/Private/Templates/BackendUser/List.fluid.html`):

**EXT:beuser/Resources/Private/Templates/BackendUser/List.fluid.html (excerpt)**

```xml
<td>
    <a href="#"
        data-contextmenu-trigger="click"
        data-contextmenu-table="be_users"
        data-contextmenu-uid="{compareUser.uid}"
        title="id={compareUser.uid}"
    >
        <be:avatar backendUser="{compareUser.uid}" showIcon="TRUE" />
    </a>
</td>
```

the relevant line being highlighted. The attribute `data-contextmenu-trigger`
triggers a context menu functionality for the current element. The
`data-contextmenu-table` attribute contains a table name of the record and
`data-contextmenu-uid` the `uid` of the record.

The attribute `data-contextmenu-trigger` has the following options:

-   `click`: Opens the context menu on the "click" and "contextmenu"
    events
-   `contextmenu`: Opens the context menu only on the "contextmenu" event

One additional data attribute can be used `data-contextmenu-context` with
values being, for example, `tree` for context menu triggered from
the page tree. Context is used to hide menu items independently for page tree
independently from other places (disabled items can be configured in TSconfig).

> [!NOTE]
> In most cases the `data-contextmenu-uid` attribute contains an integer value.
> However, in case of files and folders this attribute takes file/folder path
> as a value like `data-contextmenu-uid="1:/some-folder/some-file.pdf"`

## Disabling context menu items from TSconfig

Context menu items can be disabled in TSConfig by adding item name to the
`options.contextMenu` option corresponding to the table and context
you want to cover.

For example, disabling `edit` and `new` items for
table `pages` use:

```typoscript
options.contextMenu.table.pages.disableItems = edit,new
```

If you want to disable the items just for certain context (for example tree)
add the `.tree` key after table name like that:

```typoscript
options.contextMenu.table.pages.tree.disableItems = edit,new
```

If configuration for certain context is available, the default configuration
is not taken into account.

For more details see [TSConfig reference](https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/UserTsconfig/Options.html#useroptions-contextMenu-key-disableItems).

## Tutorial: how to add a custom context menu item

Follow these steps to add a custom menu item for pages records. You will add a
"Hello world" item which will show an info after clicking.

![The context menu now contains an additional item "Hello World"](../../Images/ManualScreenshots/Examples/ContextualMenuExtended/ContextMenuHelloWorld.png)

### Step 1: implementation of the item provider class

Implement your own item provider class. Provider must implement
`\TYPO3\CMS\Backend\ContextMenu\ItemProviders\ProviderInterface` and
can extend `\TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider`
or any other provider from EXT:backend.

See comments in the following code snippet clarifying implementation details.

**EXT:examples/Classes/ContextMenu/HelloWorldItemProvider.php**

```php
<?php

namespace T3docs\Examples\ContextMenu;

/**
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider;

/**
 * Item provider adding Hello World item
 */
class HelloWorldItemProvider extends AbstractProvider
{
  /**
   * This array contains configuration for items you want to add
   * @var array
   */
  protected $itemsConfiguration = [
    'hello' => [
      'type' => 'item',
      'label' => 'Hello World', // you can use "LLL:" syntax here
      'iconIdentifier' => 'actions-lightbulb-on',
      'callbackAction' => 'helloWorld', //name of the function in the JS file
    ],
  ];

  /**
   * Checks if this provider may be called to provide the list of context menu items for given table.
   *
   * @return bool
   */
  public function canHandle(): bool
  {
    // Current table is: $this->table
    // Current UID is: $this->identifier
    //        return $this->table === 'pages';
    return true;
  }

  /**
   * Returns the provider priority which is used for determining the order in which providers are processing items
   * to the result array. Highest priority means provider is evaluated first.
   *
   * This item provider should be called after PageProvider which has priority 100.
   *
   * BEWARE: Returned priority should logically not clash with another provider.
   *         Please check @see \TYPO3\CMS\Backend\ContextMenu\ContextMenu::getAvailableProviders() if needed.
   *
   * @return int
   */
  public function getPriority(): int
  {
    return 55;
  }

  /**
   * Registers the additional JavaScript RequireJS callback-module which will allow to display a notification
   * whenever the user tries to click on the "Hello World" item.
   * The method is called from AbstractProvider::prepareItems() for each context menu item.
   *
   * @param string $itemName
   * @return array
   */
  protected function getAdditionalAttributes(string $itemName): array
  {
    return [
      'data-callback-module' => '@t3docs/examples/context-menu-actions',
      // Here you can also add any other useful "data-" attribute you'd like to use in your JavaScript (e.g. localized messages)
    ];
  }

  /**
   * This method adds custom item to list of items generated by item providers with higher priority value (PageProvider)
   * You could also modify existing items here.
   * The new item is added after the 'info' item.
   *
   * @param array $items
   * @return array
   */
  public function addItems(array $items): array
  {
    $this->initDisabledItems();
    // renders an item based on the configuration from $this->itemsConfiguration
    $localItems = $this->prepareItems($this->itemsConfiguration);

    if (isset($items['info'])) {
      //finds a position of the item after which 'hello' item should be added
      $position = array_search('info', array_keys($items), true);

      //slices array into two parts
      $beginning = array_slice($items, 0, $position + 1, true);
      $end = array_slice($items, $position, null, true);

      // adds custom item in the correct position
      $items = $beginning + $localItems + $end;
    } else {
      $items = $items + $localItems;
    }
    //passes array of items to the next item provider
    return $items;
  }

  /**
   * This method is called for each item this provider adds and checks if given item can be added
   *
   * @param string $itemName
   * @param string $type
   * @return bool
   */
  protected function canRender(string $itemName, string $type): bool
  {
    // checking if item is disabled through TSConfig
    if (in_array($itemName, $this->disabledItems, true)) {
      return false;
    }
    $canRender = false;
    switch ($itemName) {
      case 'hello':
        $canRender = $this->canSayHello();
        break;
    }
    return $canRender;
  }

  /**
   * Helper method implementing e.g. access check for certain item
   *
   * @return bool
   */
  protected function canSayHello(): bool
  {
    //usually here you can find more sophisticated condition. See e.g. PageProvider::canBeEdited()
    return true;
  }
}

```

### Step 2: JavaScript actions

Provide a JavaScript file (ES6 module) which will be
called after clicking on the context menu item.

**EXT:examples/Resources/Public/JavaScript/context-menu-actions.js**

```javascript
/**
 * Module: @t3docs/examples/context-menu-actions
 *
 * JavaScript to handle the click action of the "Hello World" context menu item
 */

class ContextMenuActions {

  helloWorld(table, uid) {
    if (table === 'pages') {
      //If needed, you can access other 'data' attributes here from $(this).data('someKey')
      //see item provider getAdditionalAttributes method to see how to pass custom data attributes
      top.TYPO3.Notification.error('Hello World', 'Hi there!', 5);
    }
  };
}

export default new ContextMenuActions();

```

Register the JavaScript ES6 modules of your extension if not done yet:

**examples/Configuration/JavaScriptModules.php**

```php
<?php

return [
  'dependencies' => ['core', 'backend'],
  'tags' => [
    'backend.contextmenu',
  ],
  'imports' => [
    '@t3docs/examples/' => 'EXT:examples/Resources/Public/JavaScript/',
  ],
];

```

### Step 3: registration

If you have `autoconfigure: true` set in your extension's `Services.yaml` file all
classes implementing `\TYPO3\CMS\Backend\ContextMenu\ItemProviders\ProviderInterface`
get registered as context menu items automatically:

**EXT:examples/Configuration/Services.yaml**

```yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false
```

If `autoconfigure` is disabled you can manually register a context menu item provider
by adding the tag `backend.contextmenu.itemprovider`:

**EXT:my_extension/Configuration/Services.yaml**

```yaml
services:
  _defaults:
    autoconfigure: false

  MyVendor\MyExtension\ContextMenu\SomeItemProvider:
    tags:
      - name: backend.contextmenu.itemprovider

```
