SparrowLaunch
React 2026-06-15 8 min read

How to Embed Modern React Applications Inside Salesforce LWC

Written by the SparrowLaunch engineering team


Lightning Web Components (LWC) are excellent for standard forms and record pages, but building highly interactive user flows—such as custom product configurators, interactive visual calendars, or drag-and-drop workflow interfaces—can quickly become a maintenance challenge. An alternative approach is embedding a custom **React SPA (Single Page Application)** directly inside a container LWC. This allows you to leverage the full React ecosystem (state management, component libraries, visual canvas elements) while remaining securely hosted inside Salesforce. ### High-Level Architecture The integration works by bundling your React application into a single JavaScript and CSS asset file using **Vite**, uploading that bundle as a **Salesforce Static Resource**, and mounting it inside a shadow DOM element in LWC. 1. **The Container LWC**: Serves as the DOM mount target and manages the OAuth or Session ID handshake. 2. **The Apex Controller**: Handles database queries. LWC passes Apex query promises down to the embedded React app. 3. **The LWC-React Bridge**: React uses standard browser CustomEvents to request data, and the parent LWC listens to these events and returns database results back. ### Configuring Vite for Salesforce Compatibility Salesforce requires assets to load from single compiled files. In your React project, modify your `vite.config.ts` to disable file chunking: ```typescript import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { rollupOptions: { output: { entryFileNames: 'bundle.js', assetFileNames: 'bundle.[ext]', chunkFileNames: 'chunk.js', } } } }); ``` Once compiled, zip the `dist/` folder and upload it to Salesforce as a Static Resource named `ReactOpportunityBundler`. ### Communicating Between LWC and React To query data, React sends custom events that bubble up to the LWC: ```javascript // Inside React Component const requestSalesforceData = (opportunityId) => { const event = new CustomEvent('sf_query_data', { detail: { opportunityId }, bubbles: true, composed: true }); window.dispatchEvent(event); }; ``` Inside the container LWC, register a listener in the `renderedCallback()`: ```javascript // Inside LWC Controller renderedCallback() { if (this.reactLoaded) return; this.reactLoaded = true; this.template.addEventListener('sf_query_data', (event) => { const oppId = event.detail.opportunityId; // Call Apex Method getOpportunityLineItems({ oppId }) .then(result => { // Send data back to React window this.sendDataToReact(result); }); }); } ``` ### Key Security & Styling Considerations - **Shadow DOM Limits**: Salesforce wraps LWCs in a Shadow DOM. React's styling needs to be compiled directly into the JS bundle or loaded explicitly via LWC’s `loadStyle` function to prevent page styling collisions. - **CSRF & Locker Service**: Ensure your React app respects Salesforce security rules. Do not perform direct external HTTP requests unless you whitelist the domain inside Salesforce CSP Settings.

Article Tags

#React#Salesforce LWC#Vite#Web Development

Start Streamlining Your Systems

Schedule a quick 15-minute consultation to walk through your operational bottlenecks. No corporate jargon—just practical engineering advice.