Implementation of Context Menu in Browser Extension
Context menu of browser is quick way to give user action directly on selected text, link or image without opening popup. API is simple, but there are nuances with lifecycle and nesting.
Permission in manifest
{
"permissions": ["contextMenus"]
}
Without this permission, chrome.contextMenus calls are silently ignored.
Creating menu items
Menu items created in service worker on extension install. Creating on every SW restart will create duplicates:
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.removeAll(() => {
chrome.contextMenus.create({
id: 'translate-selection',
title: 'Translate "%s"',
contexts: ['selection'],
});
chrome.contextMenus.create({
id: 'save-link',
title: 'Save link to list',
contexts: ['link'],
});
chrome.contextMenus.create({
id: 'separator-1',
type: 'separator',
contexts: ['selection'],
});
});
});
%s in title is replaced with selected text (up to ~25 chars).
Context types
| Context | Triggers |
|---|---|
selection |
selected text exists |
link |
right-click on link |
image |
right-click on image |
video / audio |
media elements |
editable |
input fields, textarea |
page |
anywhere on page |
all |
everywhere |
Handling clicks
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
switch (info.menuItemId) {
case 'translate-selection':
await handleTranslate(info.selectionText, tab);
break;
case 'save-link':
await saveLink(info.linkUrl, tab);
break;
case 'search-image':
await searchImage(info.srcUrl, tab);
break;
}
});
Timeline
Simple context menu with 2-3 items: 1 day. Complex with submenus, permissions checking: 2–3 days.







