LWR Everywhere
LWR Everywhere allows you to embed Lightning web components into your web page or app using just a few lines of code. LWR Everywhere is powered by the Lightning Web Stack, which provides:
Displaying components
This section goes through the steps to display a Lightning web component on your website. No special tools or setup needed!
1. Add a container to the HTML
First, open the HTML page you want to edit. Add an empty <div> tag anywhere within the <body> to mark where you want to display a Lightning web component. For example:
<div id="embed-stats"></div>
This <div> has a unique id attribute. This allows us to find it later so we can embed a component in it.
2. Import the LWR Everywhere Module
Add a JavaScript module script to the HTML page. For example:
<script type="module" src="lwre.js"></script>
Import the authenticate and createComponent APIs from the LWR Everywhere module. For example:
import { authenticate, createComponent } from 'https://lwr-server.com/resource/path/lwr-everywhere.js';
Tip: Use a minified version of the LWR Everywhere module by importing lwr-everywhere-min.js and a debug version with lwr-everywhere-debug.js.
3. Authenticate
In order to access components from your Salesforce org, you must be authenticated. LWR Everywhere doesn’t handle authentication, so you must provide it with a Salesforce authentication token and instance URL. For example:
import { authenticate, createComponent } from 'https://lwr-server.com/resource/path/lwr-everywhere.js';
const { access_token, instance_url } = getAuthData();
authenticate({ access_token, instance_url });
Note: The authentication data is obtained from an OAuth flow into your Connected App.
4. Display a component
After authenticating, embed a Lightning web component on your website. For example:
import { authenticate, createComponent } from 'https://lwr-server.com/resource/path/lwr-everywhere.js';
const { access_token, instance_url } = getAuthData();
authenticate({ access_token, instance_url });
createComponent('my/stats', 'embed-stats', { category: 'cats', darkMode: true });
And that's it!
This one line of code displays the "my/stats" component in the <div> we created in the first step, and passes in some public properties (category and darkMode).
Tip: Check out the API reference for authenticate and createComponent.
Interactivity
After creating a component, you can interact with it.
Update component properties
Update a component's public properties to add reactivity. For example:
const container = document.querySelector('#counter-container');
const counter = createComponent('my/counter', container, { count: 6 });
counter.properties = { count: 9 };
Client-side Navigation
If the embedded component uses the LWR Client-side Router, turn on the navigation setting. Then you can navigate programmatically and subscribe to navigation events and errors. For example:
import { createComponent } from 'https://lwr-server.com/resource/path/lwr-everywhere.js';
const cmp = createComponent('my/cmp', 'container', { mode: 'compact' }, { navigation: true });
cmp.pageReference = { type: 'standard__namedPage', attributes: { pageName: 'home' } };
cmp.addEventListener('navigate', ({ detail }) => {
console.log('Navigated to page reference:', detail);
});
cmp.addEventListener('navigationerror', ({ detail: { code, message } }) => {
console.error(`Navigation error: ${code} - ${message}`);
});
UI API Adapters
Important: This feature is currently under construction!
LWR Everywhere supports the UI API adapters. For example, this code shows an embedded component requesting a list of Opportunities from a Salesforce org via the getListInfoByName wire:
import { LightningElement, wire } from 'lwc';
import { getListInfoByName } from 'lightning/uiListApi';
export default class MyData extends LightningElement {
opportunities = [];
@wire(getListInfoByName, {
objectApiName: 'Opportunity',
listViewApiName: 'AllOpportunities',
})
listView({ error, data }): void {
if (data) {
this.opportunities = data.records.records;
} else if (error) {
console.error(`Failed to fetch Opportunities: ${error.body.message}`);
}
}
}
Connected App setup
To enable authentication with LWR Everywhere, follow these steps to set up a secure Connected App:
-
Create a Connected App with OAuth Settings using these instructions and:
- If a client-side authentication flow is being used, set the "Callback URL" to the URL of the HTML page (e.g.
"https://my-website.com/page")
- Make a note of the "Consumer Key" and "Consumer Secret" (if applicable)
-
Enabled CORS for the website, if a client-side authentication flow is being used:
- Go to Setup -> CORS
- Add a new "Allowed Origin" for the website (e.g.
"https://my-website.com")
-
Setup a Content Security Policy (CSP)
- Add a
script-src CSP to the web page containing the Connected App origin, and 'unsafe-eval' to support Lightning Web Security. For example:
<meta
http-equiv="Content-Security-Policy"
content="script-src 'unsafe-eval' https://connected-app-server.com"
/>
Build your own LWR Everywhere module
For the majority of use cases, you simply import the LWR Everywhere Module from your Salesforce org. However, you can also generate your own custom LWR Everywhere module and host it yourself. For example:
import { authenticate, createComponent } from './static/my-lwr-everywhere.js';
Use the generate() API from the @lwrjs/everywhere/generate server module to build the file. For example:
import { generate } from '@lwrjs/everywhere/generate';
generate({
format: 'amd',
server: 'https://lwr-server.com',
apiVersion: 'v57.0',
apiPrefix: '/lwr',
locale: 'fr',
bundle: false,
debug: true,
minify: true,
outFile: 'static-site/public/lwrEverywhere.js',
})
.then(() => {
console.log('>> successfully built the LWR Everywhere module');
process.exit(0);
})
.catch((e) => {
console.error('>> ERROR generating the LWR Everywhere module:', e);
process.exit(1);
});
Tip: Check out the API reference for generate.
API reference
Client APIs
Import these functions from the LWR Everywhere Module.
authenticate
interface AuthData {
access_token?: string;
instance_url: string;
}
type AuthenticateFunction = (authData?: AuthData) => void;
createComponent
type CreateComponentFunction = (
specifier: string,
nodeId: string | HTMLElement,
properties?: Record<string, any>,
config?: { navigation: boolean },
) => Promise<EverywhereComponent>;
interface EverywhereComponent extends Element {
properties: Record<string, any>;
pageReference?: PageReference;
}
interface PageReference {
type: string;
attributes?: Record<string, string | null>;
state?: Record<string, string | null>;
}
Server APIs
Import these functions from @lwrjs/everywhere/generate.
generate
interface GenerationOptions {
format: 'esm' | 'amd';
server?: string;
apiVersion?: string;
apiPrefix?: string;
locale?: string;
bundle?: boolean;
debug?: boolean;
minify?: boolean;
outFile?: string;
}
type GenerateFunction = (options: GenerationOptions) => Promise<void>;