Microfrontends let a web app you already built run inside a Lightning page. Data goes in as props. Events come back out.
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.
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.
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.
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.
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.
| Attribute | What it does |
|---|---|
src | The URL of your hosted app |
title | The accessible title of the frame |
sandbox | Sandbox permissions for the iframe |
props | The data you pass in. The name is the component's attribute, so props is the one to use |
onescalatecase | Handles the event the app sends out. Lowercase, no hyphen, because the app dispatches escalatecase |
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.
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.
These are the three I triggered on purpose in my org.
| Code | Phase | What caused it |
|---|---|---|
HEARTBEAT_TIMEOUT | bootstrap | The Trusted URL was inactive. Fires after 30 seconds and is marked retryable |
SAME_ORIGIN_SRC | configuration | The src pointed at the same origin as Lightning. Fires immediately |
SESSION_BINDING_MUTATED | configuration | The 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.
- 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, withsrc,title,sandbox,props, and an event handler - Data goes in through
props. Events come out asCustomEvents only - The Trusted URL must be active, apply to
frame-src, and differ from the Lightning origin - Use
title, notshell-title, and avoid100vhbecause auto resize is on - A blank frame after 30 seconds points to the Trusted URL
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.


0 Comments