SfSkills Domains Docs GitHub

Home / lwc / lwc-web-components-interop

lwc-web-components-interop

LWC interop with non-LWC web components: consuming third-party standard custom elements in LWC, exposing LWC as custom elements externally, Shadow DOM vs native web components, polyfills, and slotting patterns. NOT for LWC-to-LWC composition (use lwc-best-practices) — use lwc/lwc-light-dom.

Open the skill folder on GitHub


LWC Web Components Interop

Activate when an LWC must consume a third-party standard web component (a custom element defined outside Salesforce's LWC framework) or expose an LWC for external consumption. Web component interop is a supported pattern but full of subtle traps — shadow DOM boundary, event bubbling, styling isolation, and polyfill behavior all differ from plain LWC.

Before Starting

Core Concepts

Custom elements in LWC

LWC supports embedding standard custom elements. The element must be defined via customElements.define(). LWC renders it like any DOM node; it is the consumer's responsibility to load the definition before first render.

Static resource loading via loadScript

loadScript (from lightning/platformResourceLoader) imports a bundled custom element from a Static Resource. The script must call customElements.define() with a namespaced tag (e.g., my-widget) to avoid collisions across components.

Shadow DOM boundary

LWC components have shadow DOM. A consumed web component may also have its own shadow DOM → nested shadow roots. Event bubbling respects both boundaries; styles are isolated on each side.

Events

Third-party web components emit CustomEvent on their host. LWC listens via onmyevent in template or this.addEventListener('myevent', ...) in connectedCallback. Event detail payloads follow CustomEvent spec.

Lightning Web Security (LWS)

LWS is the successor to Locker. It is more permissive but not unlimited; test custom elements that touch window, document, timers, or fetch.

Common Patterns

Pattern: Consume a Shoelace / Material component inside an LWC

Bundle the component JS as a Static Resource. LWC connectedCallback calls loadScript(this, staticResource) and renders <sl-button> (or equivalent). Events bridged via addEventListener.

Pattern: Wrapper LWC with SLDS theming

An LWC wraps the third-party component, applies SLDS-consistent props, and exposes a simplified API. Rest of the codebase uses the wrapper — changing libraries becomes a wrapper-only change.

Pattern: Event bridging to LWC events

Third-party component dispatches CustomEvent('value-change'). Wrapper LWC catches it and re-dispatches a Salesforce-flavored CustomEvent('valuechange') (lowercase, no dashes) for easier consumption in templates.

Decision Guidance

SituationRecommended ApproachReason
Need a specific third-party controlWrapper LWC consuming standard custom elementNative interop
Component depends on a heavy framework (React/Vue)Reconsider — write native LWC or find alternativeBridge cost exceeds value
Styling must match SLDSWrapper LWC applies SLDS props or CSS varsShadow DOM isolates
Multiple LWCs consume same third partySingle Static Resource, one define() callPrevent collisions
Component touches window/documentTest in LWS earlyLocker / LWS blocker
  1. Verify the candidate library is a true standard custom element (no framework wrapper).
  2. Prototype in a scratch org: Static Resource + loadScript + render tag.
  3. Test in Lightning Web Security context; note any blocked APIs.
  4. Build a wrapper LWC with SLDS-consistent props and event bridging.
  5. Document the wrapper's public API in JSDoc and in a README.
  6. Centralize the Static Resource load (load once per page) to avoid duplicate define() errors.
  7. Write LWC jest tests for the wrapper that mock the custom element.

Review Checklist

Salesforce-Specific Gotchas

  1. customElements.define() is global. Loading the same library twice on the same page throws "already defined" errors — centralize the load.
  2. Lightning Web Security is not identical to Locker. Components that worked under Locker may need retesting; some APIs unblock under LWS.
  3. Experience Cloud vs Lightning App context differ. Static Resources load consistently, but CSP, Locker/LWS, and loader timing can vary — test on every target surface.

Output Artifacts

ArtifactDescription
Wrapper LWC templateJS + HTML + meta for the wrapper
Static Resource bundleWeb component JS packaged for Salesforce
Event bridging specExternal → Salesforce event names
Compatibility reportLWS / Locker blockers per API

Package files