BroadcastChannel transport
Two lines of setup: createBroadcastChannelTransport("tab-sync-demo") and
addTransport(transport). No handshake, no connection management — any tab that opens the
same-named channel is immediately in the mesh.
Tab Sync Dashboard shows how postal’s BroadcastChannel transport turns cross-tab state synchronization into a straightforward pub/sub problem. Open it in two browser tabs side by side and watch state changes propagate in real time — login, theme, and preferences all stay in sync.
BroadcastChannel transport
Two lines of setup: createBroadcastChannelTransport("tab-sync-demo") and
addTransport(transport). No handshake, no connection management — any tab that opens the
same-named channel is immediately in the mesh.
The production pattern
localStorage holds the authoritative state. A new tab hydrates from storage via
loadState() and renders immediately. Live changes flow through postal so every open tab
stays consistent without polling or manual coordination.
Echo prevention in postal core
Outbound envelopes are stamped with source: instanceId in transport.ts. Inbound
envelopes matching the local instance are silently dropped. User actions just publish —
subscribers handle all state mutation regardless of whether the message was local or remote.
Wiretap observability
addWiretap() sees every message on the bus — both local publishes and messages arriving
from other tabs via the transport. The activity log in the demo is 100% wiretap with no
duplication from the subscribers.
Open http://localhost:5173 in two or more tabs.
Try:
The full source is in examples/tab-sync/ in the postal.js repository.
Key files:
src/main.ts — all postal wiring: transport, channel, subscribers, user action publishes, wiretapsrc/state.ts — AppState type and localStorage helpers (loadState, saveState)src/ui.ts — DOM layer with no postal imports; all state changes flow through callbacks