Add contextmenu items to a Chrome extension's browser action button
Asked Answered
O

4

22

A G Chrome extension can have a 'browser action'. Usually the ext developer displays the options when you click on it, meaning every action requires 2 clicks, even the default 99%-of-the-time action. Chrome itself adds a context menu with a few options: disable ext, uninstall ext, go to ext homepage etc.

Can I as ext developer add items to that context menu, so I can keep my 1-click-action under the normal/left/primary mouse click?

I know of chrome.contextMenus but that's only for context menus in the page (see property 'contexts').

I can't find it in the Chrome Extension dev guide, but you know more than I.

Oasis answered 19/10, 2013 at 16:40 Comment(0)
R
55

It is now possible, AdBlock chrome extensions has it. Below is working example of "context menu in browser action".

manifest.json:

{
    "name": "Custom context menu in browser action",
    "version": "1",
    "manifest_version": 2,
    "background": {
      "scripts": ["background.js"]
    },
    "browser_action": {
      "default_title": "Some tooltip",
      "default_popup": "popup.html"
    },
    "permissions": [
      "contextMenus"
    ],
    "icons": {
      "16": "icon16.png"
    }
}

background.js:

chrome.contextMenus.removeAll();
chrome.contextMenus.create({
      title: "first",
      contexts: ["browser_action"],
      onclick: function() {
        alert('first');
      }
});

Note that if you use an Event page, you cannot use the onclick attribute; you'll need to add a listener to chrome.contextMenus.onClicked instead.

Rajasthani answered 5/11, 2014 at 15:21 Comment(10)
That does not answer the question: the question is specifically about browserAction context menu. However, you are right that the answer is "it is now possible". Care to fix your answer?Poncho
it is about browser_actionRajasthani
Your example, however, is not (browser_action is not included in all despite what docs say). Fix the example and I'll be happy to upvote.Poncho
I fixed up formatting and added a relevant link to the chrome issue tracker. Good job on updating this old question. You might want to pick a better screen name (looks spammy)Poncho
No thanks, this site has second worst comment system (after phpbb), will not come again :(Rajasthani
Aaaaaw heellz yeeaah! That's awesome. Chrome does weird stuff every new update, but it adds awesome stuff too! Great answer, perfect score! I don't remember what I wanted to do with this though....Oasis
A note on event pages, since this took me a few to figure out. As developer.chrome.com/extensions/event_pages states, having "persistent": false under manifest.json will make background.js into an event page, possibly breaking the workings.Alkanet
I don't know why but "browser_action" didn't work for me in the contexts property. I used "page_action" and it works.Sturmabteilung
@Sturmabteilung That'll be because you're using a Page action instead of a browser action in your manifest file. They are different.Surfboarding
As of Manifest v3, the context is action, instead of browser_actionMuttonhead
J
2

Example (almost patttern) It also provides a workaround for using a simple onclick listeners (here short property “act”), for now if you use the “Event page” you can not use native onclick

const menuA = [
  { id: 'ItemF', act: (info, tab) => { console.log('Clicked ItemF', info, tab, info.menuItemId); alert('Clicked ItemF') } },
  { id: 'ItemG', act: (info, tab) => { console.log('Clicked ItemG', info, tab, info.menuItemId); alert('Clicked ItemG') } },
  { id: 'ItemH', act: (info, tab) => { console.log('Clicked ItemH', info, tab, info.menuItemId); alert('Clicked ItemH') } },
  { id: 'ItemI', act: (info, tab) => { console.log('Clicked ItemI', info, tab, info.menuItemId); alert('Clicked ItemI') } },
];

const menuB = [
  { id: 'ItemJ', act: (info, tab) => { console.log('Clicked ItemJ', info, tab, info.menuItemId); alert('Clicked ItemJ') } },
  { id: 'ItemK', act: (info, tab) => { console.log('Clicked ItemK', info, tab, info.menuItemId); alert('Clicked ItemK') } },
  { id: 'ItemL', act: (info, tab) => { console.log('Clicked ItemL', info, tab, info.menuItemId); alert('Clicked ItemL') } },
  { id: 'ItemM', act: (info, tab) => { console.log('Clicked ItemM', info, tab, info.menuItemId); alert('Clicked ItemM') } },
];


const rootMenu = [
  //
  // In real practice you must read chrome.contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT
  //
  { id: 'ItemA', act: (info, tab) => { console.log('Clicked ItemA', info, tab, info.menuItemId); alert('Clicked ItemA') }, menu: menuA },
  { id: 'ItemB', act: (info, tab) => { console.log('Clicked ItemB', info, tab, info.menuItemId); alert('Clicked ItemB') }, menu: menuB },
  { id: 'ItemC', act: (info, tab) => { console.log('Clicked ItemC', info, tab, info.menuItemId); alert('Clicked ItemC') } },
  { id: 'ItemD', act: (info, tab) => { console.log('Clicked ItemD', info, tab, info.menuItemId); alert('Clicked ItemD') } },
  { id: 'ItemE', act: (info, tab) => { console.log('Clicked ItemE', info, tab, info.menuItemId); alert('Clicked ItemE') } },
];


const listeners = {};

const contexts = ['browser_action'];

const addMenu = (menu, root = null) => {

  for (let item of menu) {

    let {id, menu, act} = item;

    chrome.contextMenus.create({
      id: id,
      title: chrome.i18n.getMessage(id),
      contexts: contexts,
      parentId: root
    });

    if (act) {
      listeners[id] = act;
    }

    if (menu) {
      addMenu(menu, id);
    }
  }

};

addMenu(rootMenu);

chrome.contextMenus.onClicked.addListener((info, tab) => {
  console.log('Activate „chrome.contextMenus -> onClicked Listener“', info, tab);
  listeners[info.menuItemId] (info, tab);
});

See some example of «chrome extension tree context menu pattern»

Jennet answered 19/6, 2018 at 20:38 Comment(0)
D
2

The 2023/Manifest v3 version of asdjfiasd's answer is similar, except that you need to remove the "browser_action" property in the manifest, and you need to use a context_type of "action", not "browser_action".

In other words, the two files look like this:

manifest.json

{
    "name": "Custom context menu in browser action",
    "version": "1",
    "manifest_version": 3,
    "background": {
      "scripts": ["background.js"]
    },
    "permissions": [
      "contextMenus"
    ],
    "icons": {
      "16": "icon16.png"
    }
}

background.js

chrome.contextMenus.removeAll();
chrome.contextMenus.create({
      title: "first",
      contexts: ["action"],
      onclick: function() {
        alert('first');
      }
});
Derna answered 7/11, 2023 at 17:52 Comment(0)
A
-1

It is not possible to add any custom entries to the context menu.

You can, however, dynamically assign a panel to the button with chrome.browserAction.setPopup. You can use an options page to allow the user to choose their preferred option (single-click action, or two-clicks & multiple actions). The fact that the options page is just two clicks away from the button is also quite nice.

Here's sample code to illustrate the concept of toggling between panel and single-click.

background.js (used in your event / background page):

chrome.browserAction.onClicked.addListener(function() {
    // Only called when there's no popup.
    alert('Next time you will see a popup again.');
    chrome.browserAction.setPopup({
        popup: 'popup.html'
    });
});

popup.html, just for the demo (use CSS to make it look better):

<button>Click</button>
<script src="popup.js"></script>

popup.js, just for the demo. JavaScript has to be placed in a separate file because of the CSP.

document.querySelector('button').onclick = function() {
    chrome.browserAction.setPopup({
        popup: '' // Empty string = no popup
    });
    alert('Next time, you will not see the popup.');
    // Close panel
    window.close();
};

As you can see in this example, the chrome.browserAction.setPopup is also available in a popup page.

PS. manifest.json, so you can copy-paste the example and play with this answer.

{
    "name": "Test badge - minimal example",
    "version": "1",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"]
    },
    "browser_action": {
        "default_title": "Some tooltip"
    }
}
Autocratic answered 19/10, 2013 at 17:31 Comment(3)
I don't like the browser action popup. It's always slow. Giving the user the choice is smart though. However, I think I'm gonna use chrome.contextMenus for the less used options, so they're always available, but the default action (which is to open the options page in my ext) is always 1 click away. Good idea though!Oasis
This is not true, you CAN add items to the contextMenuSturmabteilung
@SatA, this option became available since Oct 2014 while this answer is a year before that.Jessiajessica

© 2022 - 2024 — McMap. All rights reserved.