Design the user interface
Like Chrome's user interface, an extension user interface should be purposeful and minimal. Extensions should allow users to customize or enhance the user's browsing experience without distracting from it.
This guide explores required and optional user interface features. Use it to understand how and when to implement different user interface elements within an extension.
The extension action
The Action API controls the extension's action (toolbar icon). It can either open a popup or trigger some functionality when it's clicked.
Users can trigger an extension's action by expanding the extension menu and selecting the desired extension.
To make it easier to access an extension, the user may choose to pin the extension's action to the toolbar. Once pinned, the extension's action will appear to the left of the extension menu. Users can rearrange their pinned extensions by dragging and dropping their action icons to the desired order.
Register the action
To use the Action API, the extension's manifest must contain an "action"
key. This informs the browser that the extension will customize the action.
{
"name": "My Awesome action MV3 Extension",
...
"action": {
...
}
...
}
See the manifest section of the Action API docs for a full description of the optional properties of this field.
Activate the action conditionally
The DeclarativeContent API allows you to enable the extension's action based on the page URL or when the CSS selectors match the elements on the page.
When an extension is disabled, the icon is grayed out. If the user clicks the disabled extension, the extension's context menu will appear.
Respond to the action
It's possible to register an OnClicked
handler for when the user clicks the action item. However, this won't fire if the action has a popup (default or otherwise).
chrome.action.onClicked.addListener((tab) => {
chrome.action.setTitle({tabId: tab.id, title: `You are on tab: ${tab.id}`});
});
Action badge
Badges display a colored banner on top of the action icon. They can only be used when the "action"
is declared in the manifest.
Use badges to indicate the state of the extension. The Drink Water sample extension displays a badge with "ON" to show the user they have successfully set an alarm and displays nothing when the extension is idle. Badges can contain up to 4 characters.
You can set the text of the badge by calling chrome.action.setBadgeText()
and the banner color by calling chrome.action.setBadgeBackgroundColor()
.
chrome.action.setBadgeText({text: 'ON'});
chrome.action.setBadgeBackgroundColor({color: '#4688F1'});
Designate action icons
Icons specific to the toolbar are registered in the "default_icon"
field under "action"
in the manifest. Including multiple sizes is encouraged to scale for the 16-dip space. At minimum, 16x16 and 32x32 sizes are recommended.
{
"name": "My Awesome Extension",
...
"action": {
"default_icon": {
"16": "extension_toolbar_icon16.png",
"32": "extension_toolbar_icon32.png"
}
}
...
}
Popup
A popup is an HTML file that is displayed in a special window when the user clicks the action icon. A popup works similarly to a web page; it can contain links in style and script tags, but does not allow inline JavaScript.
The Drink Water Event example popup displays available timer options. Users set an alarm by clicking one of the provided buttons.
<html>
<head>
<title>Water Popup</title>
</head>
<body>
<img src="./stay_hydrated.png" id="hydrateImage">
<button id="sampleSecond" value="0.1">Sample Second</button>
<button id="min15" value="15">15 Minutes</button>
<button id="min30" value="30">30 Minutes</button>
<button id="cancelAlarm">Cancel Alarm</button>
<script src="popup.js"></script>
</body>
</html>
The popup is registered in the manifest under the "action"
key.
{
"name": "Drink Water Event",
...
"action": {
"default_popup": "popup.html"
}
...
}
Popups can also be set dynamically by calling action.setPopup()
.
chrome.storage.local.get('signed_in', (data) => {
if (data.signed_in) {
chrome.action.setPopup({popup: 'popup.html'});
} else {
chrome.action.setPopup({popup: 'popup_sign_in.html'});
}
});
Tooltip
Use a tooltip to give short descriptions or instructions to users when they hover over the action icon. By default, the tootip displays the name of the extension.
Provide the extension icons
An extension requires at least one icon to represent it. Provide icons in PNG format for the best visual results, although any raster format supported by Chrome is accepted. This includes BMP, GIF, ICO, and JPEG.
SVG files are not supported for any icons declared in the manifest.
Ensure your icon follows the extension icon best practices.
All icons should be square or they may be distorted. If no icons are supplied, Chrome will add a generic one to the toolbar with the first letter of the extension name.
Include additional icons in the following sizes for uses outside of the toolbar.
Icon Size | Icon Use |
---|---|
16x16 | Favicon on the extension's pages and context menu icon. |
32x32 | Windows computers often require this size. |
48x48 | Displays on the extension management page. |
128x128 | Displays on installation and in the Chrome Web Store. |
Register icons in the manifest under the "icons"
field.
{
"name": "My Awesome Extension",
...
"icons": {
"16": "extension_icon16.png",
"32": "extension_icon32.png",
"48": "extension_icon48.png",
"128": "extension_icon128.png"
}
...
}
Additional user interface features
Side panel
An extension side panel is an HTML file that provides additional functionality alongside the main content of a web page. The Dictionary side panel example allows users to right-click on a word and see the definition in the side panel.
For more samples and use cases, see the Side Panel API reference page.
Tooltips are registered in the "default_title"
field under the "action"
key in the manifest.
{
"name": "Tab Flipper",
...
"action": {
"default_title": "Press Ctrl(Win)/Command(Mac)+Shift+Right/Left to flip tabs"
}
...
}
Tooltips can also be set or updated by calling action.setTitle()
.
Omnibox
Users can invoke extension functionality through the Omnibox API. Include the "omnibox"
field in the manifest and designate a keyword. The Omnibox New Tab Search sample extension uses nt as the keyword.
{
"name": "Omnibox New Tab Search",
...
"omnibox": { "keyword" : "nt" },
"default_icon": {
"16": "newtab_search16.png",
"32": "newtab_search32.png"
}
...
}
When the user types "nt" into the omnibox, it activates the extension. To signal this to the user, it grayscales the provided 16x16 icon and includes it in the omnibox next to the extension name.
The extension listens to the omnibox.onInputEntered
event. After it's triggered, the extension opens a new tab containing a Google search for the user's entry.
chrome.omnibox.onInputEntered.addListener((text) => {
// Encode user input for special characters , / ? : @ & = + $ #
const newURL = `https://www.google.com/search?q=${encodeURIComponent(text)}`;
chrome.tabs.create({ url: newURL });
});
Context menu
You can use the ContextMenus API by granting the "contextMenus"
permission in the manifest.
{
"name": "Global Google Search",
...
"permissions": [
"contextMenus",
"storage"
],
"icons": {
"16": "globalGoogle16.png",
"48": "globalGoogle48.png",
"128": "globalGoogle128.png"
}
...
}
The 16x16 icon is displayed next to the new menu entry.
Create a context menu by calling contextMenus.create()
in the service worker. Do this in the runtime.onInstalled
event listener.
chrome.runtime.onInstalled.addListener(async () => {
for (let [tld, locale] of Object.entries(tldLocales)) {
chrome.contextMenus.create({
id: tld,
title: locale,
type: 'normal',
contexts: ['selection'],
});
}
});
const tldLocales = {
'com.au': 'Australia',
'com.br': 'Brazil',
'ca': 'Canada',
'cn': 'China',
'fr': 'France',
'it': 'Italy',
'co.in': 'India',
'co.jp': 'Japan',
'com.ms': 'Mexico',
'ru': 'Russia',
'co.za': 'South Africa',
'co.uk': 'United Kingdom'
};
The Global Google Search context menu example provides multiple context menu options based on the list in locales.js
(see above). When an extension contains more than one context menu, Chrome automatically collapses them into a single parent menu (see below).
Commands
Use the Commands API to define commands and bind them to a key combination. Register one or more shortcuts in the manifest under the "commands"
key.
{
"name": "Tab Flipper",
...
"commands": {
"flip-tabs-forward": {
"suggested_key": {
"default": "Ctrl+Shift+Right",
"mac": "Command+Shift+Right"
},
"description": "Flip tabs forward"
},
"flip-tabs-backwards": {
"suggested_key": {
"default": "Ctrl+Shift+Left",
"mac": "Command+Shift+Left"
},
"description": "Flip tabs backwards"
}
}
...
}
Use commands to provide new or alternative browser shortcuts. The Tab Flipper sample extension listens to the commands.onCommand
event in the service worker and defines functionality for each registered combination.
chrome.commands.onCommand.addListener((command) => {
// command will be "flip-tabs-forward" or "flip-tabs-backwards"
chrome.tabs.query({currentWindow: true}, tabs => {
// Sort tabs according to their index in the window.
tabs.sort((a, b) => a.index - b.index);
const activeIndex = tabs.findIndex((tab) => tab.active);
const lastTab = tabs.length - 1;
let newIndex = -1;
if (command === 'flip-tabs-forward') {
newIndex = activeIndex === 0 ? lastTab : activeIndex - 1;
} else { // 'flip-tabs-backwards'
newIndex = activeIndex === lastTab ? 0 : activeIndex + 1;
}
chrome.tabs.update(tabs[newIndex].id, {active: true, highlighted: true});
});
});
Override pages
An extension can override one of thee possible pages:
- History
- New tab
- Bookmarks
Use a custom HTML file to do this. As with a popup, it can include specialized logic and style, but does not allow inline JavaScript. Register it in the manifest under the "chrome_url_overrides"
field.
{
"name": "Awesome Override Extension",
...
"chrome_url_overrides" : {
"newtab": "override_page.html"
},
...
}
The "newtab"
field should be replaced with "bookmarks"
or "history"
when overriding those pages.
<html>
<head>
<title>New Tab</title>
</head>
<body>
<h1>Hello World</h1>
<script src="logic.js"></script>
</body>
</html>
Notifications
You can communicate relevant information to users by displaying notifications directly in their system tray. To use the Notifications API, you must declare the "notifications"
permission in the manifest.
{
"name": "Drink Water Event Popup",
...
"permissions": [
"alarms",
"notifications",
"storage"
],
...
}
Once the permission is declared, you can display a notification by calling notifications.create()
.
function showStayHydratedNotification() {
chrome.notifications.create({
type: 'basic',
iconUrl: 'stay_hydrated.png',
title: 'Time to Hydrate',
message: 'Everyday I\'m Guzzlin\'!',
buttons: [
{ title: 'Keep it Flowing.' }
],
priority: 0
});
}
Internationalize the user interface
You can use the I18n API to internationalize your extension. Create directories to house language specific messages within a folder called _locales/
, like this:
_locales/en/messages.json
_locales/es/messages.json
Format messages inside of each language's messages.json
. For example, the following code localizes the tooltip:
{
"__MSG_tooltip__": {
"message": "Hello!",
"description": "Tooltip"
}
}
{
"__MSG_tooltip__": {
"message": "Hola!",
"description": "Tooltip"
}
}
Specify the name of the message in the "default_title"
field of the manifest. The "default_locale"
field must be defined.
{
"name": "Tab Flipper",
...
"action": {
"default_title": "__MSG_tooltip__"
},
"default_locale": "en"
...
}
Continue exploring
See the Action API example for a complete demonstration of the action APIs capabilities.