The process of embedding a Lightning Web Component (LWC) connected to Apex inside an OmniScript to populate Select components provides several key benefits including, but not limited to:
- Better User Experience – Select lists can be updated dynamically based on prior user input (e.g., cascading picklists), creating a guided and responsive flow without forcing full OmniScript refreshes.
- Reusability & Modularity – The LWC encapsulates both UI logic and data access. It can be reused across different OmniScripts or FlexCards, providing consistency and reducing maintenance overhead.
- Dynamic Data Retrieval – The LWC can call Apex to query Salesforce or external systems in real time, ensuring Select options are always up to date (e.g., account types, product lists, regions).
- Performance & Scalability – Apex allows server-side filtering and business logic execution before data reaches the OmniScript, reducing payload size and improving performance for complex datasets.
This example will utilize the scenario of dynamically loading contacts from Apex into a Lightning Web Combobox component whenever an account is selected from a standard Omniscript select component.
-
-
Create a new Apex class using VS Code or Salesforce Developer Console. For this example, we have given the name of
GetPicklistValueByContactto the class. -
Within the
GetPicklistValueByContact.clsfile, implement the ‘Callable’ interface to theGetPicklistValueByContactclass. Note that implementing this interface will require implementing thecall(String action, Map\<String, Object\> args)method. The completedomniListComponent.jsfile should look like below:
-
GetPicklistValueByContact class
global class GetPicklistValueByContact implements Callable {
public Object call(String action, Map<String, Object> args) {
Map<String, Object> input = (Map<String, Object>)args.get('input');
Map<String, Object> output = (Map<String, Object>)args.get('output');
Map<String, Object> options = (Map<String, Object>)args.get('options');
return invokeMethod(action, input, output, options);
}
private Object invokeMethod(String methodName, Map<String,Object> input, Map<String,Object> output, Map<String,Object> option) {
System.debug(LoggingLevel.DEBUG,'***input**** ' + input);
// MethodName Will be same as the value that we have mentioned while calling
if (methodName == 'AccountNames') {
List< Map <String, String>> UIoptions = new List< Map <String, String>>();
for (Account acc : [Select Id, Name FROM Account ORDER BY Name LIMIT 200]) {
Map<String,String> tempMap = new Map<String,String>();
tempMap.put('name', acc.Id);
tempMap.put('value', acc.Name);
UIoptions.add(tempMap);
}
output.put('options', UIoptions);
}
if (methodName == 'ContactNames') {
String accountId = (String) input.get('accountId');
List< Map <String, String>> UIoptions = new List< Map <String, String>>();
for (Contact con : [Select Id, Name FROM Contact WHERE AccountId = :accountId ORDER BY Name LIMIT 200]) {
Map<String,String> tempMap = new Map<String,String>();
tempMap.put('value', con.Id);
tempMap.put('label', con.Name);
UIoptions.add(tempMap);
}
output.put('options', UIoptions);
}
return true;
}
}
-
Deploy this source to org (if using VS Code).
-
-
Create a new Lightning Web Component using VS Code or Salesforce Developer Console. For this example, we have named the component
omniListComponent. -
Within the
omniListComponent.htmlfile, define the UI with a simple<lightning-combobox\>component. The completedomniListComponent.htmlfile should look like below. Be sure to notice the binding declarations.
-
omniListComponent.html
<template>
<lightning-layout horizontal-align="spread" multiple-rows>
<lightning-layout-item size="12">
<lightning-combobox
name="progress"
label="Contacts"
value={contactId}
placeholder={placeholder}
options={options}
onchange={handleContactChange}
>
</lightning-combobox>
</lightning-layout-item>
</lightning-layout>
</template>
- Within the
omniListComponent.jsfile,import OmniscriptBaseMixinto interact with an Omniscript by extending theOmniScriptBaseMixincomponent. TheOmniScriptBaseMixinincludes methods to read/update an Omniscript's data JSON, pass parameters, and more.
import { OmniscriptBaseMixin } from 'omnistudio/omniscriptBaseMixin';
- On the class definition file, extend the OmniScriptBaseMixin component to wrap a Salesforce Lightning component:
export default class OmniListComponent extends OmniscriptBaseMixin(LightningElement) {
- Map all binding definitions within the omniListComponent.js file to the ones declared above in the omniListComponent.html page. Notice the @api directive attached to the accountId getter/setter. This enables external access by the Omniscript when the user selects an account from the account Select component.
@api
get accountId() {
return this._accountId;
}
set accountId(value) {
this._accountId = value;
}
get contactId() {
return this._contactId;
}
set contactId(value) {
this._contactId = value;
}
get options() {
return this._options;
}
set options(value) {
this._options = value;
}
get placeholder() {
return this.accountId ? "Select a contact" : "An account must be selected first";
}
- Add a loadContacts() method enabling the Lightning Web Component to make a remote call to your custom Apex class. Embedded Lightning Web Components must proxy through the Omniscript using the omniRemoteCall() method as they’re unable to directly connect to the Apex class.
async loadContacts(accountId) {
if (accountId) {
const params = {
input: {'accountId': accountId},
sClassName: 'GetPicklistValueByContact',
sMethodName: 'ContactNames',
options: {}
}
this.omniRemoteCall(params, true).then(response => {
this.options = response.result.options;
console.log(response);
}).catch(error => {
console.log(error);
});
}
}
- Update the accountId setter to call the loadContacts() method whenever the account Id value is updated:
set accountId(value) {
this._accountId = value;
this.loadContacts(this._accountId);
}
- Add an event handler to update the Omniscript’s data JSON when a user selects a contact. Notice this implements the omniUpdateDataJson() method.
handleContactChange(event) {
this.contactId = event.detail.value;
this.omniUpdateDataJson(this.contactId);
}
- The completed omniListComponent.js file should look like below:
omniListComponent.js
import { LightningElement, api } from 'lwc';
import { OmniscriptBaseMixin } from 'omnistudio/omniscriptBaseMixin';
export default class OmniListComponent extends OmniscriptBaseMixin(LightningElement) {
_accountId;
_contactId;
_options = [];
@api
get accountId() {
return this._accountId;
}
set accountId(value) {
this._accountId = value;
this.loadContacts(this._accountId);
}
get contactId() {
return this._contactId;
}
set contactId(value) {
this._contactId = value;
}
get options() {
return this._options;
}
set options(value) {
this._options = value;
}
get placeholder() {
return this.accountId ? "Select a contact" : "An account must be selected first";
}
async loadContacts(accountId) {
if (accountId) {
const params = {
input: {'accountId': accountId},
sClassName: 'GetPicklistValueByContact',
sMethodName: 'ContactNames',
options: {}
}
this.omniRemoteCall(params, true).then(response => {
this.options = response.result.options;
console.log(response);
}).catch(error => {
console.log(error);
});
}
}
handleContactChange(event) {
this.contactId = event.detail.value;
this.omniUpdateDataJson(this.contactId);
}
}
- For reference, the omniListComponent.js-meta.xml should look like below:
omniListComponent.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>64.0</apiVersion>
<isExposed>true</isExposed>
<runtimeNamespace>omnistudio</runtimeNamespace>
</LightningComponentBundle>
-
Deploy this source to org (if using VS Code).
-
-
Add a Select component to the desired step element. Bind this component to the Omniscript’s context variable which will with a list of accounts from the designated data mapper.

-
Add a Custom LWC component underneath the Account Select component. Configure the component with the following properties:
- Expand the Custom Lightning Web Component Properties section and add the following property:
-
-
- Make Remote Calls Within Omniscripts from Lightning Web Components
- Import Apex Methods
- Extend the Component
- Extend the OmniScriptBaseMixin Component
- Make Remote Calls from Lightning Web Components using the LWC Omniscript Action Framework
- Controlling OmniScript from Lightning Web Components (LWCs)
- Call Apex from Omniscript (Remote Action)
- How to Call Apex Method In Lightning Web Component | How to use Omniscript json data in lwc
- Calling Apex from Omniscripts with the Remote Action



