Customizing Firefox Context Menus with browser.menus API

This article explains how the browser.menus API enables developers to add custom actions to the Firefox right-click context menu. By declaring the correct permissions in the extension's manifest file, defining menu items in a background script, and registering event listeners, extensions can provide users with context-specific tools for interacting with web pages, selected text, media, and the browser interface itself.

1. Requesting Manifest Permissions

To use the browser.menus API, an extension must first request the menus permission in its manifest.json file. Without this declaration, the browser will block access to the API.

{
  "manifest_version": 3,
  "name": "Custom Context Menu Extension",
  "version": "1.0",
  "permissions": [
    "menus"
  ],
  "background": {
    "scripts": ["background.js"]
  }
}

Note that Firefox also supports the contextMenus permission as an alias for compatibility with Chrome extensions, though menus is preferred for Firefox-specific development as it unlocks additional browser UI contexts.

2. Creating Context Menu Items

Menu items are created inside the extension's background script using the browser.menus.create() method. This method accepts an object that defines the item's properties, most notably its id, title, and contexts.

browser.menus.create({
  id: "search-selected-text",
  title: "Search for '%s'",
  contexts: ["selection"]
});

Key properties include:

  • id: A unique string identifier for the menu item. This is required for identifying which item was clicked.
  • title: The text displayed in the menu. Including %s in the string will automatically inject the user's currently selected text into the menu title.
  • contexts: An array of strings specifying where the menu item should appear.
  • type: Defines the behavior of the item. Options include "normal" (default), "checkbox", "radio", and "separator".
  • parentId: Used to nest an item inside an existing menu item, creating a submenu.

3. Targeting Specific Contexts

The contexts property prevents menu clutter by ensuring custom actions only appear when relevant. The browser.menus API supports standard web page contexts as well as Firefox-specific browser UI contexts:

  • page: Appears when right-clicking anywhere on the web page that isn't a more specific element.
  • selection: Appears only when the user highlights text.
  • link: Appears when right-clicking a hyperlink.
  • image, video, audio: Appears when right-clicking specific media elements.
  • tab: A Firefox-specific context that adds the custom action when a user right-clicks a browser tab in the tab bar.
  • bookmark: A Firefox-specific context that adds the action to right-clicked bookmarks in the toolbar or sidebar.

4. Handling Menu Clicks

Creating a menu item only displays it in the UI; it does not define what happens when a user clicks it. To execute a custom action, the background script must listen for the browser.menus.onClicked event.

browser.menus.onClicked.addListener((info, tab) => {
  if (info.menuItemId === "search-selected-text") {
    const query = encodeURIComponent(info.selectionText);
    browser.tabs.create({
      url: `https://example.com/search?q=${query}`
    });
  }
});

The listener function receives two parameters:

  1. info: An OnClickData object containing context data about the click. It includes the menuItemId, the selectionText (if text was highlighted), the linkUrl (if a link was clicked), and the srcUrl (if media was clicked).
  2. tab: A tabs.Tab object representing the browser tab where the click occurred. This allows the extension to interact with that specific tab, such as injecting a script or reading its URL.

5. Updating and Removing Items Dynamically

Extensions can modify their context menu items in real time based on user actions or application state.

  • browser.menus.update(id, updateProperties): Changes the properties of an existing menu item, such as updating its title or toggling the checked state of a checkbox item.
  • browser.menus.remove(id): Deletes a specific menu item.
  • browser.menus.removeAll(): Clears all context menu items created by the extension.
  • browser.menus.onShown: An event that fires right before the context menu is displayed. Developers can use this event in combination with browser.menus.update() and browser.menus.refresh() to dynamically alter the menu based on the exact element the user right-clicked.