TL;DR, side panel is a new feature in chrome 114+ and MV3. However there is no official API to detect if side panel is open or not, but we can implement it by using chrome.runtime.connect
API for side panel
there are only four methods for side panel
- getOptions() Returns the active panel configuration.
- getPanelBehavior() Returns the extension's current side panel behavior
- open() Opens the side panel for the extension. This may only be called in response to a user action.
- setOptions() Configures the side panel.
for more details, you can check sidePanel#method.
it's clear that there no way to detect if the side panel is open or not. What's more, we have to implement the closing behavior ourselves. Though it's not a big deal, it's still a bit annoy.
Use cases
Our team is building an extension, we use short cuts to open a side panel on a web page. As you know, users sometimes create a new tab page and then enter the url, making a side panel on a new tab page doesn't make sense. So we hope side panel can be closed automatically on a new tab page and open on a web page, which means we need to know the state of side panel.
Key points
There are two key points need to be resolved:
- Whether the current page is a new tab or a web page
- The state of side panel
current page is a new tab or a web page ?
it's easy to determine if the current page is a new tab or just a web page. However, we'd better be cautious because there are many scenarios to consider:
- creating a tab
- activating a tab
- updating a tab
All of these scenarios tigger an event:
// background
chrome.tabs.onCreated.addListener(async (tab: chrome.tabs.Tab) => {
if (tab.pendingUrl == NEW_TAB_DEFAULT_URL) {
...
}
...
});
chrome.tabs.onActivated.addListener(async function (activeInfo: chrome.tabs.TabActiveInfo) {
const tab = await chrome.tabs.get(activeInfo.tabId);
if (tab.url == NEW_TAB_DEFAULT_URL) {
...
}
...
}
chrome.tabs.onUpdated.addListener((
_tabId: number,
changeInfo: chrome.tabs.TabChangeInfo,
tab: chrome.tabs.Tab,
) {
if (tab.url == NEW_TAB_DEFAULT_URL) {
...
}
...
}
the state of side panel
Initially, the side panel is closed, and we'll refer to this state as sidePanelOpened
in the rest of the article. This state can be changed by user action. When a shortcut is used, we set sidePanelOpened
to true
; otherwise, we close sidePanel and sendMessage
to side panel. Meanwhile, we use chrome.runtime.onConnect
to listen close event from side panel.All of this indicates that sidePanelOpened
is crucial.
// background
let sidePanelOpened = false;
chrome.runtime.onConnect.addListener(function (port) {
if (port.name === SIDE_PANEL_PORT) {
port.onDisconnect.addListener(() => {
sidePanelOpened = false;
});
}
});
chrome.commands.onCommand.addListener(async command => {
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
const tab = tabs[0];
const tabId = tab.id;
if (!sidePanelOpened) {
chrome.sidePanel.open({ tabId });
sidePanelOpened = true;
} else {
chrome.runtime.sendMessage({ message: CLOSE_SIDE_PANEL });
}
});
});
// side panel
chrome.runtime.onMessage.addListener((request: { message: string }) => {
if (request.message === CLOSE_SIDE_PANEL) window.close();
});
chrome.runtime.connect({ name: SIDE_PANEL_PORT });
Combining tab events with sidePanelOpened
Now the last thing we need to do is that when the url of tab becomes chrome://newtab
, we should attempt to close side panel if it is open.
So how can we determine if the side panel exists or not? luckily, we can use chrome.runtime.getContexts
export async function isSidePanelExists() {
const sidePanelContexts = await chrome.runtime.getContexts({
contextTypes: [chrome.runtime.ContextType.SIDE_PANEL],
});
return sidePanelContexts.length > 0;
}
more details about this api, it can be found here. Let's refactor our code:
if (tab.url == NEW_TAB_DEFAULT_URL) {
if (await isSidePanelExists()) {
await chrome.runtime.sendMessage({ message: CLOSE_SIDE_PANEL });
}
}
References
- runtime#method-getContexts
- sidePanel#method.
- runtime#method-connect
- Is there a way to detect if the chrome SidePanel is open
TL;DR, side panel is a new feature in chrome 114+ and MV3. However there is no official API to detect if side panel is open or not, but we can implement it by using chrome.runtime.connect
API for side panel
there are only four methods for side panel
for more details, you can check sidePanel#method.
it's clear that there no way to detect if the side panel is open or not. What's more, we have to implement the closing behavior ourselves. Though it's not a big deal, it's still a bit annoy.
Use cases
Our team is building an extension, we use short cuts to open a side panel on a web page. As you know, users sometimes create a new tab page and then enter the url, making a side panel on a new tab page doesn't make sense. So we hope side panel can be closed automatically on a new tab page and open on a web page, which means we need to know the state of side panel.
Key points
There are two key points need to be resolved:
current page is a new tab or a web page ?
it's easy to determine if the current page is a new tab or just a web page. However, we'd better be cautious because there are many scenarios to consider:
All of these scenarios tigger an event:
the state of side panel
Initially, the side panel is closed, and we'll refer to this state as
sidePanelOpened
in the rest of the article. This state can be changed by user action. When a shortcut is used, we setsidePanelOpened
totrue
; otherwise, we close sidePanel andsendMessage
to side panel. Meanwhile, we usechrome.runtime.onConnect
to listen close event from side panel.All of this indicates thatsidePanelOpened
is crucial.Combining tab events with sidePanelOpened
Now the last thing we need to do is that when the url of tab becomes
chrome://newtab
, we should attempt to close side panel if it is open.So how can we determine if the side panel exists or not? luckily, we can use
chrome.runtime.getContexts
more details about this api, it can be found here. Let's refactor our code:
References