Add Flavor to Salesforce Screen Flows With Lightning Web Components

Salesforce Screen Flows shouldn’t be tough for users to digest. In this article, we’ll show how LWC can add flavor to your Flows for a more-palatable user experience.

What We’ll Cover

  • The drawbacks of the standard Salesforce Screen Flow end-user experience.
  • How Lightning Web Components can extend Screen Flows to provide a better user experience.
  • A step-by-step guide on building a Lightning Web Component that can be used in Flows.

Salesforce Screen Flow Limitations

The out-of-the-box Flow design options are limited to the UI elements available in Flow Builder. This means that your default UI choices are simple picklists, checkbox groups, native data tables (finally), and other no-frills elements.

Salesforce is improving Flow Builder at a steady rate, as detailed in our Winter ’23 Flow Builder Improvements post, but it simply can’t keep up with user demands for slick and engaging experiences. Thankfully, just as Salesforce allowed us to include Apex code through Apex Actions in Flows, it lets us integrate custom UI code into Flows with Lightning Web Components.

Since Lightning Web Components use HTML, CSS, and JavaScript, this opens up a world of possibilities for the end-user Flow experience.

Lightning Web Components Everywhere

Even better, these Lightning Web Components aren’t limited to a single Flow. Once configured properly, they can be reused across Screen Flows and even in other areas of Salesforce, such as Lightning Record pages, Lightning applications, and Quick Action buttons.

Not only can you build your own Flow Screen components, but many developers list ready-built Flow components on the AppExchange.

Now that we know what Lightning Web Components can do for our Salesforce Screen Flows, let’s see what’s needed to make the magic happen.

Step-by-Step: Adding a Lightning Web Component to a Salesforce Screen Flow

Here’s what we’ll do:

  • Create a simple Lightning Web Component to select a favorite sauce (we said we would add flavor to our Flows).
  • Configure the component to make it visible to Flows.
  • Configure the component to accept inputs from Flows.
  • Configure the component to pass outputs back to Flows.
  • Build a simple Flow that uses this Lightning Web Component.

A Preview of the Lightning Web Component

For our component, we’ll build a screen for users to pick their favorite sauce. Unlike with picklists or checkboxes, we’ll make this visually appealing with a set of image buttons. Here’s our end result:

Bottle graphic graphics by upklyak on Freepik

Exciting, right? Admittedly, not the most useful component, but it gives a starting point to explore the possibilities.

Create Static Resources for the Lightning Web Component

We’ll save our sauce images where our Lightning Web Component can find them.

  1. Create a zip file named “sauces” with the sauce images.
  2. Go to Setup -> Static Resources -> New. Add a static resource with the settings below. Set Cache Control to Public to make the zip file available to the component.

Create the Lightning Web Component

Create the Lightning Web Component in your favorite code editor. For the JavaScript file, use the following:

import { LightningElement, api} from 'lwc';
import SAUCES from "@salesforce/resourceUrl/Sauces";

const baseSaucesUrl = '/sauces/';
 
export default class FlavorChooser extends LightningElement {
    @api headerText;
    @api buttonClicked;

    //sauce images pulled from static resources
    bbqImage = SAUCES + baseSaucesUrl + 'bbq.png';
    ketchupImage = SAUCES + baseSaucesUrl +'ketchup.png';
    mustardImage = SAUCES + baseSaucesUrl + 'mustard.png';
    mayoImage = SAUCES + baseSaucesUrl + 'mayo.png';
    soyImage = SAUCES + baseSaucesUrl + 'soy.png';
    hotSauceImage = SAUCES + baseSaucesUrl + 'hotsauce.png';

    //sauces array for display as buttons
    sauceOptions = [
        {
            "image" : this.bbqImage, 
            "value" : "bbq",
            "label" : "BBQ"
        },
        {
            "image" : this.ketchupImage, 
            "value" : "ketchup",
            "label" : "Ketchup"
        },
        {
            'image' : this.mayoImage, 
            'value' : 'mayo',
            "label" : "Mayonnaise"
        },
        {
            "image" : this.mustardImage, 
            "value" : "mustard",
            "label" : "Mustard"
        },
        {
            "image" : this.soyImage, 
            "value" : "soy",
            "label" : "Soy Sauce"
        },
    ];

    handleSauced(event) {
        this.buttonClicked = event.currentTarget.value;
    }

}

With the line below, we access the “Sauces” static resource we created earlier.

import SAUCES from "@salesforce/resourceUrl/Sauces";

Then, annotate two variables with the @api decorator. This is part one of making these variables visible to Flows. The second part happens in the component meta file.

@api headerText; 
@api buttonClicked;

The final few lines of code handle the onclick event when a sauce image is selected. This method takes the selected sauce and sets it to a class variable called buttonClicked. The buttonClicked variable will later be passed back to our Flow.

handleSauced(event) { 
    this.buttonClicked = event.currentTarget.value; 
}

The Lightning Web Component HTML file consists of a lightning-card element with a template for:each tag that iterates over the sauceOptions array, generating a button with an embedded image for each sauce. Here’s the full HTML file.

<template>

    <lightning-card>
        <h3 slot="title">
            <img src={hotSauceImage} alt="sauceImage" class="customIcon">
            {headerText}
        </h3>
        <p class="slds-var-p-horizontal_medium">
            <template for:each={sauceOptions} for:item="sauce">
                <button key={sauce.value} class="slds-button slds-button_neutral" value={sauce.value} onclick={handleSauced}>
                    <img src={sauce.image}  />
                </button>
            </template>
        </p>
    </lightning-card>
</template>

Aside from decorating variables with @api, the other part of making a Lightning Web Component available to a Flow happens in the component meta file.

<?xml version="1.0" encoding="UTF-8"?> 
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> 
    <apiVersion>55.0</apiVersion> 
    <isExposed>true</isExposed> 
    <masterLabel>Sauce Picker</masterLabel> 
    <description>
      Component that lets you pick your favorite sauce
    </description>
   <targets> 
       <target>lightning__FlowScreen</target> 
   </targets> 
  <targetConfigs> 
     <targetConfig targets="lightning__FlowScreen">  
         <property name="buttonClicked" label="Button Clicked" type="String" role="outputOnly" /> 
         <property name="headerText" label="Header Text" type="String" role="inputOnly" /> 
    </targetConfig> 
  </targetConfigs> 
</LightningComponentBundle>

The first part, <targets>, lets this component display as a Flow Builder screen element.

The second part happens in <targetConfigs>. Here, we set the variables that were previously given the @api decorator in our JavaScript as inputs, outputs, or both.

Above, the buttonClicked property is set to outputOnly. That means it can be passed to a Flow, but a Flow cannot pass data to it. The headerText property is marked inputOnly, the opposite of the outputOnly role.

To summarize: each property listed in <targetConfigs> as input or output must have a corresponding @api-decorated variable in the component JavaScript file.

Build the Screen Flow That Uses Our Lightning Web Component

Our Flow is simple, with only 2 screens. One screen will display the Lightning Web Component and configure its inputs and outputs. The other will take the component output (the selected sauce) and display it on screen.

To start, go to Setup -> Flows — New, and create a new screen Screen Flow.

After creating a new Screen Flow, click the plus icon and add a new Screen element.

Under Screen Properties on the right side of the screen, give the Flow a label, API Name, and description. Uncheck Show Header since we will be using the header from the Lightning Web Component.

On the left side of your Screen element, you see the elements that can be added to your Flow screen. Scroll to the bottom and choose the SaucePicker component that we created earlier.

Drag this component onto the Screen element.

Give the component an API name. For headerText, enter text that you will pass into the Lightning Web Component. Remember that we made this headerText attribute available to Flow Builder by decorating it with @api in the component JavaScript file and setting it as inputOnly in the component meta file.

Farther down on the right side, expand the Advanced section. Check the Manually Assign Variables box. Then, in the Button Clicked text box, create a new text variable to hold the value passed back from the Lightning Web Component.

Select Done and add one final screen. Drag a displayText element onto this screen and display the variable you used to hold the selected sauce from the previous screen.

Save the Flow and then click Run to test it out.

Click Next and see confirmation of your selection.

Summary: Adding a Lightning Web Component to a Salesforce Screen Flow

We successfully:

  1. Created a Lightning Web Component, made it visible to Flows, and passed selected inputs and outputs.
  2. Created a Flow that used this Lightning Web Component to improve the experience for end users.

This just skims the surface of what is possible when you combine the UI precision of Lightning Web Components with the ease of use of Screen Flows.

Discover more from Twenty and One

Subscribe now to keep reading and get access to the full archive.

Continue reading