Salesforce Microfrontends: Embed a React App in a Lightning Page in 4 Steps


 Microfrontends let a web app you already built run inside a Lightning page. Data goes in as props. Events come back out.

Posted on SalesforceBolt.com  |  Microfrontends  |  Salesforce Developers

▶ Watch on YouTube
Salesforce Microfrontends: Embed a React App in a Lightning Page in 4 Steps

Your team has a web app that already works. Now someone wants it on the Case page. Rebuilding it as Lightning Web Components means rebuilding something that is already done. Microfrontends give you a different route: keep the app where it is hosted, and let a small wrapper component put it on the page. I built an SLA countdown in React, hosted it on Netlify, and embedded it in a Case record page. Here is exactly how it works.

What a microfrontend is, in one line

A microfrontend is a separately built and hosted web app that renders inside a Salesforce page, with Salesforce passing data in and the app sending events back out.

Microfrontends or Multi-Framework?They solve different problems. Multi-Framework gives you a full app of its own, opened from the App Launcher. Microfrontends give you a widget inside a page that already exists, like a Case record page. This post is about the second one.

The demo

The app is an SLA tracker for Agenticwave, my fictional support company. It shows a countdown to the response target for the Case you are looking at, and it has one button: Escalate. Click it and the Case priority changes in Salesforce. The app is plain React on Netlify. Salesforce does not host a single line of it.

Step 1: Connect the app to Salesforce

The React app talks to the page through the Platform SDK, @salesforce/platform-sdk. The first thing it needs is a side effect import that starts the embedding session.

main.jsx
import "@salesforce/platform-sdk/ui-embedding";

From there the app reads the data Salesforce sends in and listens for changes. Data arrives as props, read from the view state, and the subscription hands you back an unsubscribe function so you can clean up. To send something to Salesforce, the app dispatches a CustomEvent. Only custom events are forwarded to the host.

The app must also run outside SalesforceOutside Salesforce, the view SDK resolves to an empty object. Build the app so it still renders in a normal browser tab, with a standalone mode, and local development stays painless.

Step 2: Host the app and make it public

Any host works as long as the page can be framed. I used Netlify. Two things bit me, and neither shows up in the Salesforce docs flow.

Netlify drop sites start privateA new Netlify drop site is team-only and returns a 401 until you make it public. The iframe just shows an error. Also, your host must not send an X-Frame-Options header, or the browser refuses to frame the app.

Step 3: Write the wrapper component

The wrapper is a tiny LWC. Its template is one element, the base component lightning-ui-embedding.

caseSlaTracker.html
<template>
  <lightning-ui-embedding
    src={appUrl}
    title="Case SLA tracker"
    sandbox="allow-popups"
    props={caseProps}
    onescalatecase={handleEscalate}>
  </lightning-ui-embedding>
</template>
AttributeWhat it does
srcThe URL of your hosted app
titleThe accessible title of the frame
sandboxSandbox permissions for the iframe
propsThe data you pass in. The name is the component's attribute, so props is the one to use
onescalatecaseHandles the event the app sends out. Lowercase, no hyphen, because the app dispatches escalatecase
Use title, not shell-titleIf you have seen older samples that use shell-title, those come from the Developer Preview, which is not compatible with the GA component. In my tests shell-title compiled without an error and did nothing. Use title.

In the JavaScript file, caseProps is a getter that returns a fresh plain object with the case number, priority, and created date. Return a new object each time the data changes so the app receives the update.

Step 4: Allow the app with a Trusted URL, then add it to the page

Salesforce will not frame an app it does not trust. In Setup, create a Trusted URL for your app's exact origin and make sure it is active and applies to frame-src. The origin must also be different from your Lightning origin.

Then open the Case record page in the Lightning App Builder, drop the wrapper component where you want the widget, and save. Auto resize is on by default, so the frame grows to fit the app.

Two layout trapsBecause auto resize is on, avoid 100vh and svh in the app's CSS. The frame resizes to the content, and a viewport height unit creates a loop. And the iframe is transparent, so give the app's body an explicit white background.

Three errors you will hit, and what they mean

The wrapper reports problems as a sf-embedding.component.error event. The detail carries a phase, a code, a message, and whether the error is retryable. Because the event name contains dots, you cannot bind it in the template. Add the listener in the constructor on this.template, with capture set to true.

caseSlaTracker.js
constructor() {
  super();
  this.template.addEventListener(
    "sf-embedding.component.error",
    (event) => { console.log(event.detail); },
    true
  );
}

These are the three I triggered on purpose in my org.

CodePhaseWhat caused it
HEARTBEAT_TIMEOUTbootstrapThe Trusted URL was inactive. Fires after 30 seconds and is marked retryable
SAME_ORIGIN_SRCconfigurationThe src pointed at the same origin as Lightning. Fires immediately
SESSION_BINDING_MUTATEDconfigurationThe src was changed after the component mounted

The practical lesson: a blank frame after half a minute almost always means the Trusted URL. Check that first.

What I tested, and what I did not

I tested all of this in a Developer Edition org on API 67.0, which is Summer '26, with @salesforce/platform-sdk 12.11.0. I have not tested it on Winter '27. The Salesforce documentation describes embedding a UI bundle as Beta and React only, so check the current status before you plan a production rollout around it.

salesforcebolt-lwc
batra-kapil/salesforcebolt-lwc
Key takeaways
  • Microfrontends keep your existing web app hosted where it is and put it on a Lightning page
  • The wrapper is one element, lightning-ui-embedding, with src, title, sandbox, props, and an event handler
  • Data goes in through props. Events come out as CustomEvents only
  • The Trusted URL must be active, apply to frame-src, and differ from the Lightning origin
  • Use title, not shell-title, and avoid 100vh because auto resize is on
  • A blank frame after 30 seconds points to the Trusted URL
Microfrontends UI Embedding React LWC Salesforce Developers

Verified against the Salesforce Developer documentation: Get Started with UI Embedding, Exchange Data, and UI Embedding Error Codes. Behavior described as tested was observed in my own org on Summer '26.

Watch Complete Video Below

 If you have any question please leave a comment below.

If you would like to add something to this post please leave a comment below.
Share this blog with your friends if you find it helpful!

Post a Comment

0 Comments