Content scripts and background scripts can't directly access each other's state. However, they can communicate by sending messages. One end sets up a message listener, and the other end can then send it a message. The following table summarizes the APIs involved on each side:
Let's update our example to show how to send a message from the background script.
First, edit background.js
so that it has these contents:
browser.contextMenus.create({
id: "eat-page",
title: "Eat this page"
});
function messageTab(tabs) {
browser.tabs.sendMessage(tabs[0].id, {
replacement: "Message from the extension!"
});
}
function onExecuted(result) {
let querying = browser.tabs.query({
active: true,
currentWindow: true
});
querying.then(messageTab);
}
browser.contextMenus.onClicked.addListener(function(info, tab) {
if (info.menuItemId == "eat-page") {
let executing = browser.tabs.executeScript({
file: "page-eater.js"
});
executing.then(onExecuted);
}
});
Now, after injecting page-eater.js
, we use tabs.query()
to get the currently active tab, and then use tabs.sendMessage()
to send a message to the content scripts loaded into that tab. The message has the payload {replacement: "Message from the extension!"}
.
Next, update page-eater.js
like this:
function eatPageReceiver(request, sender, sendResponse) {
document.body.textContent = "";
let header = document.createElement('h1');
header.textContent = request.replacement;
document.body.appendChild(header);
}
browser.runtime.onMessage.addListener(eatPageReceiver);
Now, instead of just eating the page right away, the content script listens for a message using runtime.onMessage
. When a message arrives, the content script runs essentially the same code as before, except that the replacement text is taken from request.replacement
.
Since tabs.executeScript()
is an asynchronous function, and to ensure we send message only after listener has been added in page-eater.js
, we use onExecuted()
which will be called after page-eater.js
executed.
If we want send messages back from the content script to the background page, we would use runtime.sendMessage()
instead of tabs.sendMessage()
, e.g.:
browser.runtime.sendMessage({
title: "from page-eater.js"
});
Note: These examples all inject JavaScript; you can also inject CSS programmatically using the tabs.insertCSS()
function.