Overview

xTabEvent is a singleton backed by one shared BroadcastChannel (mates:xtab / MATES_XTAB_CHANNEL). Use trigger(type, data?) to publish and __subscribe((type, data) => …) (or on(…, [xTabEvent])) to listen — including from other mates packages like mates-db.

Same-origin only. Payloads use the structured clone algorithm — plain objects / primitives, not functions or DOM nodes. Discriminate messages with a namespaced type string (e.g. mates-db:sync).

Unlike plain event().__subscribe, xTabEvent.__subscribe registers cleanup on the component host when one exists.

Compared to event()

API
Delivery
Notes
event() In-process Create typed channels per concern. Same JS context only.
xTabEvent Cross-tab One shared bus — filter by type. Falls back to local-only when BroadcastChannel is unavailable (SSR).

xTabEvent — cross-tab sync

Shared singleton bus — open the same page in two tabs and call xTabEvent.trigger(type, data) in one; every tab’s subscribers receive (type, data). The demo below runs in one preview tab.

import { html, atom, on, xTabEvent, renderApp } from 'mates';

const App = () => {
const log = atom(['Open this in another tab to see cross-tab sync']);

on((type, data) => {
if (type !== 'demo:ping') return;
const entry = `${type}: ${data} at ${new Date().toLocaleTimeString()}`;
log.set((prev) => [entry, ...prev.slice(0, 4)]);
}, [xTabEvent]);

return () => html`
<div class="m-col m-gap">
<div class="card card-body alert alert-warning">
<span class="tag tag-warning m-b-5">Cross-tab sync</span>
<p class="muted">
Shared <code>xTabEvent</code> bus — one BroadcastChannel for all mates apps.
</p>
</div>
<button class="btn-primary" @click=${() => xTabEvent.trigger('demo:ping', Date.now())}>
Ping all tabs
</button>
<div class="card card-body">
<span class="overline">Event log</span>
${log().map((e) => html`<div class="mono">${e}</div>`)}
</div>
</div>
`;
};
renderApp(App, document.getElementById('app'));

xTabEvent.__subscribe

Direct subscribe with auto-cleanup when a component host exists. Filter by type string.

import { html, atom, xTabEvent, renderApp } from 'mates';

const App = () => {
const last = atom('—');

// __subscribe auto-registers cleanup when a component host exists
xTabEvent.__subscribe((type, data) => {
if (type === 'demo:note') last.set(String(data));
});

return () => html`
<div class="m-col m-gap">
<p class="muted m-t-5">Last note: <strong>${last()}</strong></p>
<button class="btn-primary"
@click=${() => xTabEvent.trigger('demo:note', 'hello from this tab')}>
Broadcast note
</button>
</div>
`;
};
renderApp(App, document.getElementById('app'));