3 Simple Ways to Communicate Between Browser Tabs in JavaScript

Posted by

Learn how to make multiple tabs talk to each other, no backend, no frameworks, just pure JavaScript.

Learn how to make multiple tabs talk to each other, no backend, no frameworks, just pure JavaScript.

Introduction

Open your app in two browser tabs, make a change in one, and the other still shows old data, frustrating, right?

Whether it’s dark mode toggles, logout events, or live cart updates, browser tabs don’t share state by default. Each tab runs in its own JavaScript world, isolated from the others.

Many developers think they need WebSockets or server-side events to keep things synced. But the truth is, modern browsers already give us built-in ways to communicate between tabs, instantly and securely.

In this post, you’ll learn three simple ways to make tabs exchange messages and stay in sync using nothing but JavaScript.


1. Using the storage Event (The Classic Approach)

When one tab changes localStorage, other tabs can detect it through the storage event.

It’s the simplest way to pass messages or trigger actions between tabs.

Example

// Tab 1: send a message
localStorage.setItem('theme', 'dark');

// Tab 2: listen for changes
window.addEventListener('storage', (event) => {
if (event.key === 'theme') {
console.log('Theme changed to:', event.newValue);
document.body.dataset.theme = event.newValue;
}
});

When you update localStorage In one tab, all other tabs are listening for the The storage event will pick up the change.

Why It Works

Browsers fire a storage event in all open pages from the same origin whenever localStorage changes.

Pros

  • Easy to use, no setup required
  • Works in all major browsers

Cons

  • Doesn’t fire in the same tab where you call setItem
  • Slight delay in some browsers
  • Limited to simple data messages

Use it when: you just need lightweight state sync, like theme or preference updates.


2. Using the BroadcastChannel API (The Modern Way)

The BroadcastChannel API lets you send messages instantly between tabs (or even iframes and workers) that share the same origin.

Think of it like a local pub/sub system built into the browser.

Example

// Create a channel
const channel = new BroadcastChannel('app_channel');

// Listen for messages
channel.onmessage = (event) => {
console.log('Received:', event.data);
};

// Send a message
channel.postMessage({ type: 'UPDATE_THEME', value: 'dark' });

Now, any tab connected to 'app_channel' will instantly receive that message.

Real-World Example: Sync Logout Across Tabs

const channel = new BroadcastChannel('user_sync');

function logoutUser() {
localStorage.removeItem('token');
channel.postMessage({ type: 'LOGOUT' });
window.location.reload();
}

channel.onmessage = (e) => {
if (e.data.type === 'LOGOUT') {
localStorage.removeItem('token');
window.location.reload();
}
};

Logging out in one tab automatically logs you out everywhere.

Pros

  • Real-time, event-based communication
  • Works in all modern browsers
  • Cleaner and faster than the storage event

Cons

  • Not supported in very old browsers (like IE)

Use it when: you need instant two-way communication, logout sync, notifications, and live settings.


3. Using Shared Workers (For Advanced Use Cases)

When you need shared logic, background computation, or persistent state across tabs, Shared Workers are your tool.

They allow multiple tabs to connect to the same worker file, sharing a single process.

Example

sharedWorker.js

let ports = [];

onconnect = (event) => {
const port = event.ports[0];
ports.push(port);
port.onmessage = (e) => {
// Broadcast to all connected ports
ports.forEach(p => p.postMessage(e.data));
};
};

main.js

const worker = new SharedWorker('sharedWorker.js');
worker.port.start();

worker.port.onmessage = (e) => {
console.log('Received:', e.data);
};

// Send a message
worker.port.postMessage('Hello from tab!');

All connected tabs will receive the same message in real time.

Pros

  • Powerful for multi-tab coordination
  • Allows shared caching or computations

Cons

  • Slightly more setup
  • Not supported on Safari iOS yet

Use it when: building complex dashboards, editors, or apps that require shared logic across tabs.


4. Which Method Should You Use?

Use Case Best Method: Simple settings or theme sync storage event Real-time tab communication BroadcastChannel Shared data or background logic Shared Worker

For 90% of web apps, BroadcastChannel hits the sweet spot: simple, clean, and fast.


5. Bonus: A Tiny Helper Class

Here’s a small utility that uses BroadcastChannel under the hood. Plug it into any app.

class TabMessenger {
constructor(channelName) {
this.channel = new BroadcastChannel(channelName);
}

send(type, data) {
this.channel.postMessage({ type, data });
}

listen(type, callback) {
this.channel.onmessage = (e) => {
if (e.data.type === type) callback(e.data.data);
};
}

close() {
this.channel.close();
}
}

// Usage
const messenger = new TabMessenger('app_channel');

messenger.listen('UPDATE_THEME', (theme) => {
document.body.dataset.theme = theme;
});

function toggleTheme() {
const theme = document.body.dataset.theme === 'light' ? 'dark' : 'light';
document.body.dataset.theme = theme;
messenger.send('UPDATE_THEME', theme);
}

Now, toggling the theme in one tab updates all tabs instantly, pure client-side sync.


6. Browser Support Summary

Always check support on MDN before shipping production code.


Conclusion

You don’t need a backend or WebSocket setup to make your tabs communicate.

Between the storage event, BroadcastChannel, and Shared Workers, you have three levels of tab communication power from simple preference syncing to advanced background coordination.

Start with the easiest one that fits your use case, and your users will enjoy a smoother, more connected experience across tabs.

Pro Tip: Combine BroadcastChannel with the storage event as a fallback for older browsers.


Call to Action

Have you tried any of these tab-syncing techniques?
Share your favorite method (or your gotchas) in the comments and bookmark this post for your next multi-tab project.

Leave a Reply

Your email address will not be published. Required fields are marked *