Messaging is a very important part of Chrome extension that can cause a lot of confusion
However it’s so much easier than it seems if you know what you’re doing
I will try my best to explain it to you in simple terms
You can think of it as the central nervous system that connects the various parts of your code the background script the popup or the content scripts
The basics
The basics are super simple
You can send a message from any component and you can listen to a message from any other component
Now a message can contain any valid JSON object such as strings numbers boolean arrays or objects that can be represented in a string
This is very useful so you can come up with ways how you can differentiate between the various messages
Sending messages
To get started I will create a helper method that sends a message when a note is updated
I head over to my utils folder and create a new file
Send note update message
In this file I will use a lot of redundant code
Sorry for that it’s only for demonstration purposes
// utils/sendNoteUpdateMessage.ts
import getPageKey from './getPageKey';
import { storage } from 'wxt/storage';
const sendNoteUpdateMessage = async (tabId: number) => {
const tab = await browser.tabs.get(tabId);
if (!tab.url) return;
const pageKey = getPageKey(tab.url);
const notesStorage = await storage.getItem('sync:notesStorage') || {};
const note = notesStorage[pageKey];
const message = {
type: 'noteUpdated',
pageKey,
note
};
await browser.tabs.sendMessage(tabId, message);
};
export default sendNoteUpdateMessage;
So what I have now is the note data that belongs to the given tab ID and I can send a message by using the sendMessage method
Receiving messages
Now let’s listen for messages in the content script
// content/index.ts
export default defineContentScript({
matches: ['https://*/*'],
main() {
const pageKey = getPageKey(window.location.href);
const showRibbon = () => {
if (document.getElementById('tabnotes-ribbon')) return;
const ribbon = document.createElement('div');
ribbon.id = 'tabnotes-ribbon';
ribbon.textContent = 'Has Note';
document.body.appendChild(ribbon);
};
const hideRibbon = () => {
const ribbon = document.getElementById('tabnotes-ribbon');
if (ribbon) {
ribbon.remove();
}
};
// Listen for messages
browser.runtime.onMessage.addListener((message) => {
// Ignore messages for other pages
if (message.type !== 'noteUpdated' || message.pageKey !== pageKey) {
return;
}
// Show or hide ribbon based on whether note exists
if (message.note) {
showRibbon();
} else {
hideRibbon();
}
});
}
});
Perfect
Now when a note is updated the content script receives the message and shows or hides the ribbon accordingly
Calling from popup
When the user types in the popup we need to send the message
// popup/main.ts
noteText.addEventListener('keyup', async () => {
const [tab] = await browser.tabs.query({
active: true,
currentWindow: true
});
if (!tab.id || !tab.url) return;
// Save to storage...
await storage.setItem('sync:notesStorage', notesStorage);
// Update icon and send message
await changeIcon(tab.id);
await sendNoteUpdateMessage(tab.id);
});
Calling from background
We also want to send messages when tabs change
// background.ts
export default defineBackground(() => {
browser.tabs.onActivated.addListener(async (activeInfo) => {
await changeIcon(activeInfo.tabId);
await sendNoteUpdateMessage(activeInfo.tabId);
});
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url && tab.active) {
changeIcon(tabId);
sendNoteUpdateMessage(tabId);
}
});
});
Perfect
Now the ribbon updates automatically when you switch tabs navigate to new pages or edit notes
Message flow
Here’s how messages flow through TabNotes
- User types in popup → Popup saves to storage
- Popup calls sendNoteUpdateMessage
- Background sends message to content script
- Content script shows or hides ribbon
It’s that simple
What’s next
We’ve connected all the parts of our extension with messaging
The ribbon now updates in real time when notes change
In the next chapter we’ll create custom pages for our extension like an options page or welcome page