11 Understanding Chrome Extensions Context Menus

Context Menu is the menu that appears when a user right clicks (alternative clicks) on an element in a webpage.

https://developer.chrome.com/docs/extensions/develop/ui/context-menu

In this article we will cover the chrome.contextMenus API. https://developer.chrome.com/docs/extensions/develop/ui/context-menu. An API responsible for context menus for chrome extensions.

There are 4 major functions normally used in this API chrome.contextMenus.createchrome.contextMenus.update chrome.contextMenus.removeAll and chrome.contextMenus.onClicked.addListener. 3 of which, as you can see handle displaying the contextMenu and the latter is an event handle that runs when one of the context menu options has been selected.

Declaring Context Menus in Manifest.json

Well first things first, for one to use the chrome.contextMenus API they have to declare it first in the manifest.json file

{
...
"permissions": [
"contextMenus"
],
...
}

Menu Item Types

There are 4 different type of menu item types normalcheckboxradio and separator. If you’ve coded HTML before these are similar to the input types. Below is an image showing the different types of context menu item types.

Context Menu Item Types

You’ll notice that you can not see the separator type in the image. That is because it is an empty menu type used to separate checkbox groups and radio groups but more on that later.

In code you define a type either in the chrome.contextMenus.create or chrome.contextMenus.update functions.

chrome.contextMenus.create({
id: 'my-checkbox',
title: 'Checkbox',
"type": "checkbox",
contexts: ['page'],
});

selectable text

Context Types

What context types refers to on which element(s) should the context menu item appear on. For instance,

You might what a context menu that only appears when a user selects text

Or one that appears when a user right clicks on an input field.

With that being said let look at the major context typesimagevideolinkpage and audio I believe are self explanatory, then trigger the context menu item to show up when a user right clicks on any of those elements on webpage.

Another important one is selection this is for a user you have selected text and then have right clicked on it.

editable is for users that have right clicked into an input field

action is for the context menu for when a user right clicks on the extension popup icon in the toolbar.

action context menu option for icon in toolbar

Creating Context Menu in Code

In most cases you want to create a the context menu options when the extension has just been installed. You’d write this in your background scripts

chrome.runtime.onInstalled.addListener((details) => {

chrome.contextMenus.create({
id: 'insert',
title: 'Insert Secret Word',
type: 'normal',
contexts: ['editable'],
});

chrome.contextMenus.create({
id: 'media',
title: 'Get URL',
type: 'normal',
contexts: ['image', 'video'],
});
});

Keep in mind that chrome.contextMenus.create and chrome.contextMenus.updatefunctions return a promise or in other words the functions run asynchronously. So sometimes you might want for a menu to be created first before creating the next one.

chrome.runtime.onInstalled.addListener(async (details) => {

await chrome.contextMenus.create({
id: 'insert',
title: 'Insert Secret Word',
type: 'normal',
contexts: ['editable'],
});

await chrome.contextMenus.create({
id: 'media',
title: 'Get URL',
type: 'normal',
contexts: ['image', 'video'],
});
});

Nesting Menus

In certain instances it is a good a idea to nest your context menu to keep them organize for the user.

The way we go this is by add parentId to the menu item we are creating. So let’s say you want to create menu with two children menu items you’d set the parentId of the two child elements equal to the id of the parent. That sounded confusing so it is best to just show you. Here is a code snippet below.

Parent items must have type “normal”

chrome.contextMenus.create({
id: 'parent',
title: 'Parent',
type: "normal",
contexts: ['action'],
});

chrome.contextMenus.create({
id: 'child1',
parentId: "parent",
title: 'Child 1',
type: "checkbox",
contexts: ['action'],
});

chrome.contextMenus.create({
id: 'child2',
parentId: "parent",
title: 'Child 2',
type: "checkbox",
contexts: ['action'],
});
Nested Context Menu

Also there is a limit to how many parent items (top level menu items) you can create. As of the writing on this article it should be 6. You can find out my running this code in your background scripts and checking your console out

console.log(chrome.contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT)

Page Specific Menu Items

If you want to context menu items to only show up on specific pages you’ll need to specify the a URL patterns in the documentUrlPatterns for chrome.contextMenus.create or chrome.contextMenus.update functions.

Here is a code snippet to create context menu items that will only show either on Google or Facebook.

chrome.contextMenus.create({
id: 'google',
title: 'Only Google',
type: 'normal',
documentUrlPatterns: ["https://*.google.com/", "https://*.google.com/*"],
contexts: ['page'],
});

chrome.contextMenus.create({
id: 'fb',
title: 'Only Facebook',
type: 'normal',
documentUrlPatterns: ["https://www.facebook.com/", "https://www.facebook.com/*"],
contexts: ['page'],
});

Menu Button Groups

By arranging multiple radio menu items together you’ll create a what we call a button group.

await chrome.contextMenus.create({
id: 'menu-types',
title: 'Menu Types',
type: 'normal',
contexts: ['page'],
});

await chrome.contextMenus.create({
id: 'radio1',
parentId: "menu-types",
title: 'Radio 1',
type: "radio",
contexts: ['page'],
});


await chrome.contextMenus.create({
id: 'radio2',
parentId: "menu-types",
title: 'Radio 2',
type: "radio",
contexts: ['page'],
});
Radio Button Group for context menu

Radio Menu behave the same way <input type="radio" /> in HTML do. If arranged in one after the other, only one gets selected when clicked.

But if you separate them between another type of menu item then only radio menus next to each other behave as the on radio group. Here are some examples and code snippets.

Three Radio Buttons in one Group

Three Radio Buttons in one Group
await chrome.contextMenus.create({
id: 'menu-types',
title: 'Menu Types',
type: 'normal',
contexts: ['page'],
});

await chrome.contextMenus.create({
id: 'radio1',
parentId: "menu-types",
title: 'Radio 1',
type: "radio",
contexts: ['page'],
});

await chrome.contextMenus.create({
id: 'radio2',
parentId: "menu-types",
title: 'Radio 2',
type: "radio",
contexts: ['page'],
});

await chrome.contextMenus.create({
id: 'radio3',
parentId: "menu-types",
title: 'Radio 3',
type: "radio",
contexts: ['page'],
});

Two Groups of Radio Menus Items

Here are two groups of radio menu items that have been separated by other type of menu item

    chrome.contextMenus.create({
id: 'radio1',
title: 'Radio 1',
type: "radio",
contexts: ['page'],
});

chrome.contextMenus.create({
id: 'radio2',
title: 'Radio 2',
type: "radio",
contexts: ['page'],
});

// separates here...
chrome.contextMenus.create({
id: 's',
title: 'Separator',
type: "separator",
contexts: ['page'],
});

chrome.contextMenus.create({
id: 'radio3',
title: 'Radio 3',
type: "radio",
contexts: ['page'],
});

chrome.contextMenus.create({
id: 'radio4',
title: 'Radio 4',
type: "radio",
contexts: ['page'],
});

When Menu menu is clicked

Now lets cover one of the most crucial parts on the chrome.contextMenus API the onclick listener. We can make all the sorts of menu items until kingdom come, but it serves no purpose unless happens when the menu item is clicked.

How we write in on code. You would put this in your background script.

chrome.contextMenus.onClicked.addListener((info, tab) => {
let checked = info.checked;
let editable = info.editable;
let linkUrl = info.linkUrl;
let mediaType = info.mediaType;
let menuItemId = info.menuItemId;
let pageUrl = info.pageUrl;
let selectionText = info.selectionText;
let parentMenuItemId = info.parentMenuItemId;
let wasChecked = info.wasChecked;
});

You can refer here, to know what kind of data info and tab hold. If you want more information in the tab argument, you’d need to set the tabs permission.

Sample Project

The Google Chrome Team provide source code to a sample project you can run for yourself here: https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/api-samples/contextMenus.

Leave a Reply

Your email address will not be published. Required fields are marked *

More Articles & Posts