lwc-cross-tab-state-sync

Use when an LWC needs to react to events that happen in another browser tab — record updates, login state, draft autosave, console-tab navigation. Triggers: 'sync data across tabs', 'BroadcastChannel LWC', 'storage event LWC', 'one tab updates the other', 'console workspace tab close detection'. NOT for state sync within the same Lightning page (use Lightning Message Service) or for server-pushed updates (use CometD or refreshApex).

Best use case

lwc-cross-tab-state-sync is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when an LWC needs to react to events that happen in another browser tab — record updates, login state, draft autosave, console-tab navigation. Triggers: 'sync data across tabs', 'BroadcastChannel LWC', 'storage event LWC', 'one tab updates the other', 'console workspace tab close detection'. NOT for state sync within the same Lightning page (use Lightning Message Service) or for server-pushed updates (use CometD or refreshApex).

Teams using lwc-cross-tab-state-sync should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/lwc-cross-tab-state-sync/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/lwc/lwc-cross-tab-state-sync/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/lwc-cross-tab-state-sync/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How lwc-cross-tab-state-sync Compares

Feature / Agentlwc-cross-tab-state-syncStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when an LWC needs to react to events that happen in another browser tab — record updates, login state, draft autosave, console-tab navigation. Triggers: 'sync data across tabs', 'BroadcastChannel LWC', 'storage event LWC', 'one tab updates the other', 'console workspace tab close detection'. NOT for state sync within the same Lightning page (use Lightning Message Service) or for server-pushed updates (use CometD or refreshApex).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# LWC Cross-Tab State Sync

Activate when a Lightning Web Component must react to something that happens in *another browser tab* — for example, the user updates a record in tab A and tab B has a stale view. The skill produces a same-origin sync implementation using `BroadcastChannel` (preferred) or the `storage` event (fallback), wired into LWC lifecycle hooks with proper cleanup.

---

## Before Starting

Gather this context before working on anything in this domain:

- Whether the sync needs to be cross-window (different browser tabs) or cross-component (same Lightning page). Lightning Message Service (LMS) handles same-page; cross-tab needs browser APIs.
- Whether the data is sensitive. Anything written to `localStorage` is readable by any LWC on the same origin. PII should not flow through this channel.
- The user's likely browsers. `BroadcastChannel` is supported in Chrome, Edge, Firefox, Safari. Older corporate IE/legacy Edge environments fall back to `storage` events.
- Whether the LWC runs inside the Service Console. Console workspace tabs are separate `<iframe>` documents — same-origin but distinct windows. Both APIs work but the receiver count differs.

---

## Core Concepts

### `BroadcastChannel` vs. `storage` event

| API | Direction | Cleanup | Fallback |
|---|---|---|---|
| `BroadcastChannel('name')` | Same-origin pub-sub across tabs | Explicit `.close()` in `disconnectedCallback` | None — must polyfill via storage |
| `window.addEventListener('storage', ...)` | Fires when *another* tab writes to localStorage / sessionStorage | `removeEventListener` in `disconnectedCallback` | Universal browser support |

`BroadcastChannel` is the modern, structured-clone-aware API. The `storage` event fires only when *another* tab modifies storage (your own tab does not receive its own writes), making it a workable fallback for browsers without `BroadcastChannel`.

### LWC lifecycle integration

Subscribe in `connectedCallback`. Unsubscribe in `disconnectedCallback`. Failing to unsubscribe leaks the channel reference; over a long-lived workspace tab, that's a memory leak that compounds.

### Salesforce same-origin behavior

All Lightning experience tabs share the same origin (`*.lightning.force.com`). `BroadcastChannel` and `storage` events flow freely between them. Console workspace subtabs run inside their own iframes but on the same origin; the channel reaches them too.

---

## Common Patterns

### Pattern: post-save invalidation

**When to use:** Tab A saves a Case. Tab B is showing the same Case from a stale wire.

**How it works:** On save success in tab A, post `{type:'record-updated', recordId:'500...'}` to a `BroadcastChannel('record-updates')`. Tab B's component subscribes to the channel, filters on the recordId it cares about, and calls `refreshApex(this.wiredCase)` to re-fetch.

**Why not the alternative:** Polling every 30 seconds wastes API calls for records that didn't change.

### Pattern: logout fan-out

**When to use:** User clicks logout in tab A; tab B should redirect to the login page instead of showing a stale dashboard.

**How it works:** On logout, post `{type:'session-ended'}`. Every component subscribed handles the message by clearing local state and navigating away.

### Pattern: draft-state coordination

**When to use:** User has a long form half-filled in tab A; opens tab B to do something else; comes back.

**How it works:** On every form change (debounced), write `{recordId, draft, timestamp}` to localStorage. On tab focus, read storage; if a draft exists newer than the page-load timestamp, prompt the user to restore.

---

## Decision Guidance

| Situation | Recommended Approach | Reason |
|---|---|---|
| Modern browsers only, structured payload | `BroadcastChannel` | Cleanest API; no storage residue |
| Need IE11 / very old corporate browser | `storage` event | Universal support |
| Need persistence across reload | localStorage + storage event | Channel data is ephemeral |
| Within same Lightning page only | Lightning Message Service | LMS is the supported same-page mechanism |
| Need server-pushed updates from other users | CometD / Pub-Sub gRPC / Streaming API | Cross-tab solves only same-user, same-browser |

---

## Recommended Workflow

1. Confirm the sync is genuinely cross-tab. If it's cross-component on the same page, switch to LMS. If it's cross-user, switch to a server-side event channel.
2. Pick the API: `BroadcastChannel` if browser support permits; otherwise `storage` event.
3. Define the message schema. Always include a `type` discriminator and a timestamp. Never include PII.
4. Wire subscribe in `connectedCallback`, unsubscribe in `disconnectedCallback`. Tests must cover both.
5. Ignore your own messages. `BroadcastChannel` does not echo to the sender; the `storage` event does not fire for the writing tab. Either way, design the handler to be idempotent in case the platform changes.
6. Add a feature-detection fallback. Wrap `typeof BroadcastChannel !== 'undefined'`; on environments without it, drop to a no-op or storage-based polyfill.
7. Test in Service Console with multiple subtabs open — that's where most cross-tab bugs surface.

---

## Review Checklist

- [ ] Subscribe/unsubscribe paired across `connectedCallback` / `disconnectedCallback`
- [ ] Message schema versioned and PII-free
- [ ] Feature detection for `BroadcastChannel` with a defined fallback
- [ ] Idempotent handler — receiving the same message twice doesn't break state
- [ ] Tested in at least two browser tabs and (if applicable) Service Console subtabs
- [ ] No business logic that *requires* the sync to fire — treat as best-effort enhancement

---

## Salesforce-Specific Gotchas

1. **`BroadcastChannel` does not echo to sender** — Tab A posting and reading from the same channel will not receive its own message. Test with two distinct tabs always.
2. **`storage` event payload is the *new value*, not a structured message** — If you write the entire object as JSON, parse it; if you write only a key, the value won't tell you what changed.
3. **Service Console subtab close is invisible to siblings** — A subtab closing does not fire any cross-tab event by itself; you must explicitly post a message before close in the workspace API hook.
4. **`localStorage` is shared across browser profiles only when same Chrome profile** — Cross-profile users see independent storage; cross-tab sync within a single user's session is the only guaranteed scope.
5. **Locker Service / Lightning Locker restrictions** — Older Locker versions sandboxed `BroadcastChannel`; the modern Lightning Web Security policy permits it but verify in the org's actual security context.

---

## Output Artifacts

| Artifact | Description |
|---|---|
| Channel implementation module | The wrapper around `BroadcastChannel` with feature-detection fallback |
| Message schema | TypeScript-style JSDoc describing the discriminator + payload |
| Test scaffolding | Jest with a mocked `BroadcastChannel` that fires across simulated tabs |

---

## Related Skills

- lwc/message-channel-patterns — for *same-page* component communication via Lightning Message Service
- lwc/lwc-imperative-apex — for the `refreshApex` pattern usually triggered by the cross-tab event
- lwc/lifecycle-hooks — for the connectedCallback/disconnectedCallback discipline that prevents leaks

Related Skills

omnistudio-asynchronous-data-operations

8
from PranavNagrecha/AwesomeSalesforceSkills

Use Integration Procedures queues, DataRaptor Chain, and Remote Actions with async patterns for long-running OmniStudio flows. NOT for simple DataRaptor reads.

omniscript-session-state

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when an OmniScript must persist mid-flow state across refresh, navigation, multi-device resume, or abandonment recovery. Covers session objects, staging data, OmniScript tracking, and resume URLs. Does NOT cover OmniScript UI step layout (see omniscript-design) or general Flow pause/resume (see flow-transaction-finalizer-patterns).

flexcard-state-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing FlexCard actions, conditional visibility, and state that must survive navigation, refresh, or parent/child card transitions. Triggers: 'flexcard state', 'flexcard conditional visibility', 'flexcard actions', 'flexcard refresh', 'child flexcard state'. NOT for raw LWC state or for OmniScript step state.

lwc-state-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Share state across LWCs using pub/sub, Lightning Message Service, @wire, and reactive stores. NOT for in-component reactivity.

lwc-reactive-state-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

How LWC reactivity actually works after Spring '20 (API v48+) — every class field is reactive on reassignment, but @track is still required for in-place mutation of plain object/array contents, and Date / Set / Map mutations are NEVER observed. Covers the renderedCallback infinite-loop trap, reactive-getter caching rules, and when @track is genuinely needed today. NOT for @wire reactive parameters (see lwc/wire-adapters), NOT for Lightning Data Service caching (see lwc/ldws-and-uirecordapi), NOT for cross-component reactive state (see lwc/message-channel-patterns and lwc/state-management-with-modules).

scheduled-erp-sync-pattern

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing a recurring (15-minute / hourly / nightly) data exchange between Salesforce and an external ERP system (Oracle EBS, SAP, NetSuite, Workday, Dynamics, etc.) where Salesforce is the *initiator* and pulls or pushes deltas on a schedule. Covers the full pattern: scheduled Apex → Queueable callout chain → REST request to ERP → upsert into a staging custom object → downstream reconciliation; plus watermark management (timestamp / cursor / full-refresh modes), idempotency via External ID, retry with exponential backoff, dead-letter custom object, and the volume thresholds that should redirect you to Bulk API 2.0, Change Data Capture, or MuleSoft. Triggers: 'integration to oracle erp every 15 minutes', 'scheduled sync pattern enterprise erp', 'pull netsuite invoices into salesforce nightly', 'apex schedulable callout to sap', 'how do i sync salesforce contacts to workday hourly', 'design a polling integration to my erp'. NOT for one-shot ETL imports (use data/data-loader-bulk-api), NOT for real-time inbound from ERP via Platform Events / Pub-Sub API (use integration/platform-events-publish-subscribe), NOT for outbound *event-driven* push (use integration/change-data-capture-consumer-pattern), NOT for MuleSoft / iPaaS architecture decisions (use architect/mulesoft-vs-native-integration-decision). When the data volume routinely exceeds 10K records per cycle or sub-minute latency is required, explicitly route to the Streaming / CDC / iPaaS skills instead.

callout-limits-and-async-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or troubleshooting Apex callouts that approach governor limits: choosing between synchronous callouts, @future, Queueable, Continuation, or async chaining strategies. NOT for HTTP request construction or Named Credential setup (use named-credentials-setup).

flow-cross-object-updates

8
from PranavNagrecha/AwesomeSalesforceSkills

Cross-object DML in Flow: updating parent from child or child from parent via Get/Update Records, lookup traversal in formulas, and bulkification. NOT for Apex cross-object updates. NOT for Process Builder (migrate-workflow-pb covers migration). Use when building flows that must write to a related record.

cross-cloud-deployment-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when sequencing a deployment that spans multiple Salesforce clouds — Sales Cloud, Service Cloud, and Experience Cloud — and encountering reference errors, cascading metadata failures, or DigitalExperienceBundle ordering problems. Triggers: 'ExperienceBundle deployment fails with no Network found', 'cross-cloud metadata dependency error', 'how do I deploy Experience Cloud with Sales Cloud together', 'DigitalExperienceBundle missing CustomSite reference', 'how to sequence multi-cloud deployment correctly'. NOT for single-cloud deployments (use pre-deployment-checklist), NOT for OmniStudio or Health Cloud deployment specifics (use health-cloud-deployment-patterns), NOT for package-based multi-cloud release strategy (use multi-package-development).

marketing-cloud-data-sync

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring, diagnosing, or extending Marketing Cloud Connect Synchronized Data Sources — the mechanism that pulls Salesforce CRM object records into read-only Synchronized Data Extensions (SDEs) in Marketing Cloud. Triggers on: synced data extension not updating, contact or lead records missing from Marketing Cloud, sync failures in Contact Builder, 250-field limit questions, CRM-to-MC data latency concerns. NOT for manual imports via Import Activity, NOT for SFTP-based data loads, NOT for Data Cloud (CDP) real-time data streams, NOT for direct Apex callouts into Marketing Cloud.

cdc-data-sync-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when designing or troubleshooting the replication lifecycle for CDC-based data synchronization: day-0 full load, incremental delta processing, replay ID management, gap event fallback, and ordering/deduplication using transactionKey and sequenceNumber. NOT for CDC admin setup (entity selection, channel configuration, edition limits — see integration/change-data-capture-integration). NOT for Apex CDC trigger subscribers.

cross-cloud-data-deployment

8
from PranavNagrecha/AwesomeSalesforceSkills

Cross-cloud data deployment: designing the data handoff when an implementation spans Sales Cloud, Service Cloud, Marketing Cloud, Data Cloud, Commerce Cloud. Shared keys, identity resolution, sync vs event, CDC, Data Cloud as hub. NOT for single-cloud data model design (use sales-cloud-core-setup or service-cloud-core-setup). NOT for integration pattern selection (use integration-pattern-selection decision tree).