Skip to content
JavaScript · open-source library

tabs-broadcast

Send events between the open tabs of your web app, and let exactly one of them do the work that must not run twice. A tiny TypeScript library over the BroadcastChannel API.

MIT Zero dependencies TypeScript, Nuxt module

4.71,296 votes
Live demo npm Source on GitHub

Open the demo in two or three tabs to see messages travel between them and the primary tab move when you close it. Using Nuxt? Install tabs-broadcast-nuxt instead.

Video
What it is

Messages between tabs

Publish an event in one tab and every other open tab of the same site receives it, over the browser's BroadcastChannel API. No server, no polling.

One primary tab

Exactly one tab is elected primary through the Web Locks API, with a localStorage fallback. Close it and another tab takes over, so syncing or polling runs once, not per tab.

Typed events and layers

Pass an event map as a generic for autocomplete and payload checks. Layers split one channel into independent streams, which suits micro-frontends.

Quick start
  1. 01

    Install the package

    npm install tabs-broadcast (or pnpm, yarn, bun). For Nuxt 3 or 4, install the tabs-broadcast-nuxt module instead: it adds a client plugin and a useTabsBroadcast() composable.

  2. 02

    Create the bus

    new TabsBroadcast() in your app. It is a singleton: creating it again returns the same instance, and destroy() tears it down.

  3. 03

    Subscribe in every tab

    bus.on(type, callback) registers a listener. once() fires a single time, onList() registers many, and the "*" wildcard catches every event in a layer.

  4. 04

    Emit from the primary tab

    bus.emit(type, payload) sends to all tabs. By default only the primary tab may emit, so check bus.primary first or set emitByPrimaryOnly to false.

import TabsBroadcast from 'tabs-broadcast'

const bus = new TabsBroadcast()

// Subscribe in every tab
bus.on('cart:update', ({ payload }) => {
  console.log('cart changed:', payload)
})

// Publish: only the primary tab emits by default
if (bus.primary)
  bus.emit('cart:update', { items: 3 })
FAQ
Is tabs-broadcast free?
Yes. It is open source under the MIT licence, has zero dependencies and ships ESM and UMD builds with TypeScript types.
Which browsers does it support?
Every modern browser with BroadcastChannel: Chrome, Edge, Firefox and Safari 15.4 or newer. It is safe to import during SSR: without a window it does nothing.
Why elect a primary tab?
So that work which must not run in duplicate, such as server sync, background polling or notifications, runs in one tab only. When that tab closes or reloads, another one is promoted automatically.
Is the channel private?
No. BroadcastChannel is same-origin, but any script on that origin can post to it if it knows the name. Treat every payload as untrusted input and use a hard-to-guess channelName.
Rovniy/tabs-broadcast API reference Report a bug

Newsletter

Occasional notes on engineering, game tech, and new tools — no spam, unsubscribe anytime.

Ravy

Engineering manager, founder, and software developer building web platforms, game systems, real-time services, and automation tools. 15 years of shipped work — currently at Gaijin.net.

Get in Touch

Building an MVP, shipping a game feature, or automating a team workflow? Open source or paid — let's talk.

Contact Me
© 2020-2026 XPLOIT FZE. All trademarks, names and logos belong to their respective copyright holders.