How to send a message from a background script to a content script in a sidebar panel

I’ve read on MDN that sending a message from a background script to a content script is done using:

const sending = browser.tabs.sendMessage(
  tabId,     // integer
  message,   // any
  options    // optional object
);

but, unless I’m mistaken, sidebar panels don’t have a tabId, so how do you target the sidebar panel as a destination for a message from a background script?

I would guess it works similar to popups which also don’t have tabId, so like this:

This will broadcast it through, so make sure to send a specific message that will be processed only by the sidebar.

You can do that by sending an object with some specific field, for example:

browser.runtime.sendMessage({type: 'sidebar_action_x', data: 'hello'});

Thank you for your quick response, Juraj.

The documentation says: “Extensions cannot send messages to content scripts using this method. To send messages to content scripts, use tabs.sendMessage.”

I tried the following:

const requestFilter = {
    tabId: -1,
    types: ['main_frame'],
    urls: ['http://*/*', 'https://*/*'],
};

browser.webRequest.onCompleted.addListener(
    sendMessageToSidebar,             // function
    requestFilter
);

function sendMessageToSidebar() {
    browser.tabs.sendMessage({ action: 'injectCSS', data: targetUrl });
}

but I got an error saying that the receiving end didn’t exist, so it seems that the message is sent before the content script is injected in the sidebar panel. Mind you, I’m not sure that I can send a message this way without specifying a tabId.

I ended up using your hack instead and it’s working very well. Thank you, again!

Oh, that’s right, I forgot about that.

And the other method won’t work either, because “browser.tabs.sendMessage” requires “tabId” as first argument.

But, the content script should be able to use browser.runtime.sendMessage to send message to the background script which can then “reply” to that message - by returning a Promise with a value in the event handler.

Alternatively, you can use this API to establish a connection which can be used to send messages:

This bug report contains a working implementation that uses runtime.connect()


The report claims that it doesn’t work, and that was probably true 6 years ago, but it works as of Firefox 114.0.1