Mastering Multi-tab Communication - Part 3

Sridhar MuraliSridhar Murali
3 min read

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.

0
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