Mastering Multi-tab Communication - Part 3

In the previous parts of this series, we explored what the BroadcastChannel API is, why it's useful, and how to work with it to send and receive messages between browser tabs. Now in Part 3, let's put that knowledge into action.
We’ll build a Master-Slave Tab Architecture, where:
Only one tab (the master) holds control (say, for handling a WebSocket or a call).
Other tabs (the slaves) can listen or request control when the master is closed.
This architecture is commonly used in apps with real-time features—like CRMs with VoIP dialers, collaborative editors, or dashboard apps that should avoid duplicated actions across tabs.
🏗️ Architecture Goals
Only one tab acts as the master at any time.
All tabs can communicate via
BroadcastChannel
.If the master closes, another tab takes over.
Any tab can request to become master when needed.
📦 Step-by-Step Implementation
1. Set up a BroadcastChannel
const bc = new BroadcastChannel('app-tab-channel');
2. Identify Tabs with a Unique ID
Each tab will get a unique identifier for tracking.
const TAB_ID = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
3. Define Roles
let isMaster = false;
let masterTabId = null;
4. Handle Incoming Messages
bc.onmessage = (event) => {
const { type, tabId } = event.data;
switch (type) {
case 'hello':
// A new tab has joined
if (isMaster) {
bc.postMessage({ type: 'master-announce', tabId: TAB_ID });
}
break;
case 'master-announce':
masterTabId = tabId;
isMaster = (tabId === TAB_ID);
break;
case 'request-master':
if (!isMaster && masterTabId == null) {
becomeMaster();
}
break;
case 'master-left':
if (!isMaster) {
requestMasterRole();
}
break;
}
};
5. Announce Yourself
When a new tab is opened:
bc.postMessage({ type: 'hello', tabId: TAB_ID });
6. Electing a Master
The first tab to open can claim the role:
function becomeMaster() {
isMaster = true;
masterTabId = TAB_ID;
bc.postMessage({ type: 'master-announce', tabId: TAB_ID });
}
If a tab sees there's no master, it can request the role:
function requestMasterRole() {
bc.postMessage({ type: 'request-master', tabId: TAB_ID });
}
7. Handle Master Closing
Before the master tab is closed, notify others:
window.addEventListener('beforeunload', () => {
if (isMaster) {
bc.postMessage({ type: 'master-left', tabId: TAB_ID });
}
});
🔄 Full Example Flow
Tab A opens and becomes master.
Tab B opens and receives a
master-announce
from A.Tab A closes. It emits
master-left
.Tab B receives
master-left
and requests master role.Tab B becomes the new master.
🧪 Testing Tips
✅ Open multiple tabs in your app.
✅ Watch the console logs (you can add logs for every state change).
✅ Close the master tab and ensure a new master is elected.
✅ Real-world Uses
WebRTC Calls: Only master manages socket connections and call states.
Push Notifications: Only master listens to incoming messages.
Live Dashboards: Prevents duplicate data fetching across tabs.
🔚 Wrapping Up
You’ve now built a robust multi-tab control system using the BroadcastChannel API. This is a powerful pattern for managing resource-intensive features in web applications—ensuring you don't double up work across tabs.
Subscribe to my newsletter
Read articles from Sridhar Murali directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sridhar Murali
Sridhar Murali
Passionate Frontend Engineer with over 4.5 years of experience in frontend development and a strong previous experience in Quality Assurance of 4 years (2016-2020). Skilled in building responsive, high-quality applications using JavaScript frameworks like Ember.js and React.js, combining meticulous attention to detail from a QA background with a commitment to delivering seamless user experiences. Recognized for writing efficient, accessible code, strong debugging skills