Storage Cross-Tab Communication in JavaScript
Communicate between browser tabs using storage
AdvancedLocalStorage/SessionStorageExample 10 of 10
storage-cross-tab-communication.js
1// Method 1: Basic cross-tab messaging2class CrossTabMessenger {3 constructor(channel) {4 this.channel = channel;5 this.listeners = [];6 this.setupListener();7 }89 setupListener() {10 window.addEventListener('storage', (e) => {11 if (e.key === this.channel && e.newValue) {12 const message = JSON.parse(e.newValue);13 this.listeners.forEach(listener => listener(message));14 }15 });16 }1718 send(message) {19 localStorage.setItem(this.channel, JSON.stringify({20 ...message,21 timestamp: Date.now(),22 tabId: this.getTabId()23 }));24 // Clear immediately to allow same message again25 setTimeout(() => localStorage.removeItem(this.channel), 100);26 }2728 onMessage(callback) {29 this.listeners.push(callback);30 }3132 getTabId() {33 let tabId = sessionStorage.getItem('tabId');34 if (!tabId) {35 tabId = 'tab_' + Date.now() + '_' + Math.random();36 sessionStorage.setItem('tabId', tabId);37 }38 return tabId;39 }40}4142const messenger = new CrossTabMessenger('app-messages');43messenger.onMessage((message) => {44 console.log('Message received:', message);45});4647messenger.send({ type: 'user-updated', data: { name: 'John' } });4849// Method 2: Broadcast channel API (modern)50if ('BroadcastChannel' in window) {51 const channel = new BroadcastChannel('app-channel');5253 channel.postMessage({ type: 'notification', message: 'Hello from tab 1' });5455 channel.onmessage = function(e) {56 console.log('Broadcast received:', e.data);57 };58}5960// Method 3: Shared state manager61class SharedState {62 constructor(key) {63 this.key = key;64 this.state = this.loadState();65 this.listeners = [];66 this.setupListener();67 }6869 loadState() {70 const stored = localStorage.getItem(this.key);71 return stored ? JSON.parse(stored) : {};72 }7374 setupListener() {75 window.addEventListener('storage', (e) => {76 if (e.key === this.key) {77 this.state = JSON.parse(e.newValue);78 this.notifyListeners();79 }80 });81 }8283 setState(updates) {84 this.state = { ...this.state, ...updates };85 localStorage.setItem(this.key, JSON.stringify(this.state));86 this.notifyListeners();87 }8889 getState() {90 return this.state;91 }9293 subscribe(callback) {94 this.listeners.push(callback);95 }9697 notifyListeners() {98 this.listeners.forEach(listener => listener(this.state));99 }100}101102const sharedState = new SharedState('app-state');103sharedState.subscribe((state) => {104 console.log('State updated:', state);105});106107sharedState.setState({ user: 'John', theme: 'dark' });108109// Method 4: Leader election110class TabLeader {111 constructor() {112 this.leaderKey = 'tab-leader';113 this.heartbeatInterval = null;114 this.checkLeader();115 }116117 checkLeader() {118 const leader = localStorage.getItem(this.leaderKey);119 const now = Date.now();120121 if (!leader) {122 this.becomeLeader();123 } else {124 const [leaderTabId, timestamp] = leader.split(':');125 const age = now - parseInt(timestamp);126127 // If leader is inactive for 5 seconds, take over128 if (age > 5000) {129 this.becomeLeader();130 }131 }132133 // Check every second134 setTimeout(() => this.checkLeader(), 1000);135 }136137 becomeLeader() {138 const tabId = this.getTabId();139 localStorage.setItem(this.leaderKey, tabId + ':' + Date.now());140 this.startHeartbeat();141 console.log('Became leader');142 }143144 startHeartbeat() {145 this.heartbeatInterval = setInterval(() => {146 const tabId = this.getTabId();147 localStorage.setItem(this.leaderKey, tabId + ':' + Date.now());148 }, 2000);149 }150151 isLeader() {152 const leader = localStorage.getItem(this.leaderKey);153 if (!leader) return false;154 const [leaderTabId] = leader.split(':');155 return leaderTabId === this.getTabId();156 }157158 getTabId() {159 let tabId = sessionStorage.getItem('tabId');160 if (!tabId) {161 tabId = 'tab_' + Date.now();162 sessionStorage.setItem('tabId', tabId);163 }164 return tabId;165 }166}167168const tabLeader = new TabLeader();
Output
Message received: { type: 'user-updated', data: { name: 'John' }, timestamp: 1234567890, tabId: 'tab_1234567890' }
Broadcast received: { type: 'notification', message: 'Hello from tab 1' }
State updated: { user: 'John', theme: 'dark' }
Became leaderWhat's going on
Cross-tab communication syncs data.
Methods
Storage events: Cross-tab
BroadcastChannel: Modern API
Shared state: Common pattern
Leader election: Coordination
Storage Events
Fires in other tabs
Not in same tab
Use for messaging
BroadcastChannel
Modern API
Better performance
Easier to use
Browser support varies
Use Cases
Sync user state
Notifications
Real-time updates
Coordination
Best Practices
Use BroadcastChannel if available
Fallback to storage events
Handle errors
Clean up listeners