Adding Lightning Web Components to Flow Screens

For the last two years, Flow creators have been able to add lightning component to Flow Screens. This has powerfully extended the capability of screens. We’ve had a great time creating reusable components as a community, and many of those components are available for use to all parties.

The underlying web technology enabling these components, known as Aura, has served Salesforce well, but it’s more than 5 years old, and that’s a long time when it comes to changes in web technology. Salesforce recently released a major upgrade to its web technology called Lightning Web Components, and the Flow team made it possible to embed this new generation of components into Flow screens. Let’s take a look at how it’s done.

In this demonstration, we create an LWC that allows the user to manually add and manage sharing settings on a record. This allows a Sharing button to be placed on Lightning record pages. The guts of this component consist of code written by resident Salesforce evangelist Shane McLaughlin.

To get an LWC to appear in Flow’s Screen Builder, you add a ‘lightning_FlowScreen’ target to the component’s meta file:

Attributes and Properties

To expose attributes from the LWC, you first use @api in the LWC’s javascript, as is standard for any property you want to make accessible outside of the component:

Then you additionally specify which of these public properties should be made visible in Flow by adding a targetConfig section:

The type field supports the same types that Flow supports with aura components. That includes specific Sobjects like “Contact” and specific SObject collections like “Account[]”. You can also use this interface to directly publish access to your apex class data structures for declarative manipulation in Flow . This extremely powerful technology is discussed at length here.

Note the following syntax for specifying SObjects and Apex Classes:

  • @salesforce/schema/<name of sObject>
  • apex://<name of Apex class>

Add array notation if it is a collection:  []

Namespaces

With a namespaced org you have to include the namespace in the type string using the namespace prefix. So, for SObjects it would look like type=”@salesforce/schema/myNs__CoolCustomObject__c”. For apex types:”apex://myNs__MyApexClass”

Input and Output Control via Roles

The ‘role’ parameter can be added to property elements inside of targetConfigs. It has been created specifically to provide support for Flow’s ability to limit access to inputOnly or outputOnly. If no role is specified, the property is available in both directions.

Troubleshooting
If you hit this error: unable to find field dataType for complex reference: foo, you may need to set a default value on your attribute. For example, this error will occur if the value attribute is not set to an empty string here:

Considerations When Working With Targets

Be Careful about Mixing Your Targets

The support mentioned above for SObjects and Apex Classes works only for Flow and not for other targets like lightning__RecordPage. So something like this will fail:

This can be hard to debug because each target has its own validation and the errors reported back don’t specify which target is the source of the difficulty. So you can get into a situation where you think your new Flow interface is complaining when it’s actually a problem being reported by App Builder.

Each property has to meet the requirements of each Target that mentions it.

Example: App Builder (and thus lightning__RecordPage, lightning__AppPage, lightning__HomePage) requires that if you add a ‘required’ attribute you also have to add a ‘default’ attribute. Flow does not have this requirement. If you try to add the same attribute to both sections, you’ll have to satisfy the combination of their constraints.

A good practice is to separate the App Builder targets from the Flow target, like this:

This helps but does not eliminate all possible interaction headaches. In the example above, Flow is forced to add a default attribute to editTabName because editTabName is also used in the AppBuilder targets, where that required/default issue is enforced. But it makes it easier to debug because you can comment out one set and see which validation is causing problems.

Events and Notification

Unlike Aura, the parent component doesn’t automatically learn when something changes in the child component. This takes some getting used to for old Aura hands.

There are two scenarios where this matters. For all of your LWC’s, think of the Flow Runtime as the parent container that needs to be notified about changes that need to be available external to your component. Any attribute that you intend to be used downstream in the Flow must be constantly reported to the Flow Runtime whenever the value changes in your component. (Likewise, if you have an lwc with lwc child components, you’ll have similar issues).

To notify Flow of changes in the value of an attribute in your component, the component must fire the FlowAttributeChangeEvent event.

In the following example, a ToDo LWC dispatches a FlowAttributeChangeEvent when a new item is added to the list of To Do’s:

import { LightningElement, api, track } from 'lwc';
import { FlowAttributeChangeEvent, FlowNavigationNextEvent } from 'lightning/flowSupport';
export default class Todos extends LightningElement {
    @api
    availableActions = [];
    @api
    get todos() {
        return this._todos;
    }
    set todos(todos = []) {
        this._todos = todos;
    }
    @track _todos = [];
    get hasTodos() {
        return this._todos && this._todos.length > 0;
    }
    handleUpdatedText(event) {
        this._text = event.detail.value;
    }
    handleAddTodo() {
        this._todos.push(this._text);
        // notify the flow of the new todo list
        const attributeChangeEvent = new FlowAttributeChangeEvent('todos', this._todos);
        this.dispatchEvent(attributeChangeEvent);
    }
    handleGoNext() {
        // check if NEXT is allowed on this screen
        if (this.availableActions.find(action => action === 'NEXT')) {
            // navigate to the next screen
            const navigateNextEvent = new FlowNavigationNextEvent();
            this.dispatchEvent(navigateNextEvent);
        }
    }
}

See additional pieces of the To Do example

Validation

To link an LWC into Flow’s validation framework, create a function called “validate” in your js file:

@api
validate() {
    if(/* true conditions */) { 
         return { isValid: true }; 
        } 
    else { 
    //If the component is invalid, return the isValid parameter as false and return an error message. 
         return { 
               isValid: false, 
               errorMessage: '/*A message that helps your user enter a valid value or explains what went wrong.*/' 
                }; 
     }}) 
}

Navigation

To programmatically transition a Flow with an LWC component, you dispatch an event using this syntax:

import { LightningElement, api } from 'lwc';
import { FlowNavigationNextEvent } from 'lightning/flowSupport';

export default class NameOfYourComponent extends LightningElement {

   @api
   handleGoNext() {
       const nextNavigationEvent = new FlowNavigationNextEvent();
       this.dispatchEvent(nextNavigationEvent);
   }
}

The supported events are:

  • FlowNavigationNextEvent
  • FlowNavigationBackEvent
  • FlowNavigationFinishEvent
  • FlowNavigationPauseEvent

Examples

Set Sharing Manually

Sample Gists

https://gist.github.com/alexed1/e3e580103375120ca2dc1374bb4f73ff

13 replies
  1. Chris V
    Chris V says:

    Any chance you can elaborate on the validation portion? Im an Admin, not a Dev but I was able to build a good selection of LWC but still cannot get required to work like I did in my aura components.

    Reply
    • Alex Edelstein
      Alex Edelstein says:

      Are you still having trouble? Note that around the time you posted this, we fixed the example above to show that you need to put @api on the validate method. If that doesn’t solve the problem, feel free to post some code here.

      Reply
      • Chris V
        Chris V says:

        Good news! Adding @api made the validate method work! I have isRequired working now. Next I need to get min and max values working.

        import {
        LightningElement,
        track,
        api
        } from “lwc”;

        export default class Input extends LightningElement {
        @api value = “”;
        @api initials = “”;
        @api label = “”;
        @api compId = “”;
        @api min = “”;
        @api max = “”;
        @api isRequired = false;
        @track length = 0;

        @api
        handleChange(event) {
        this.value = event.target.value;
        this.length = this.value.length;
        }

        @api
        validate() {
        if (this.isRequired === false || this.length >= 1) {
        return {
        isValid: true
        };
        // eslint-disable-next-line no-else-return
        } else {
        return {
        isValid: false,
        errorMessage: ‘Please complete: ‘ + this.label
        };
        }
        }
        }

        Reply
  2. ivelin ganev
    ivelin ganev says:

    Hello guys, i have a question.
    Aura property –
    LWC property –

    Please can you help me, why LWC property always give me “You specified an invalid type for” that response?
    How can i get a collection of the Flow Action “get records” and pass it to the Javascript?

    Reply
    • Alex Edelstein
      Alex Edelstein says:

      What does your targetConfig look like? Note that the lwc syntax is a little unfamiliar. If you’re passing a collection of Contacts, for example, you would put @salesforce/schema/Contact[] in the type attribute of your property.

      Reply
      • ivelin ganev
        ivelin ganev says:

        Thank you for the response.
        My property looks like ( property name=”allContacts” type=”Contact[]” ).
        Now i tried with ( property name=”allContacts” type=”@salesforce/schema/Contact[]” ) but the response was “You specified an invalid type for ‘allContacts'”

        Reply
  3. Ivelin Ganev
    Ivelin Ganev says:

    Hello everyone! Can you tell me can I still use aura:attribute name=”selectedRows” type=”SObject[]” but with the new syntax of LWC? I mean I would receive random sObject and want to handle it.

    Many thanks!

    Reply
  4. Jens Becker
    Jens Becker says:

    Hi Alex,

    Are you aware, if we can use custom metadata type arrays for input properties? I tried

    Which I can deploy, however, the input possibility in the flow disappears. So I assume, this works for APEX defined and “real” sObjects only.
    Am I correct?

    Thanks,

    Jens

    Reply
  5. Gordon Vaynapel
    Gordon Vaynapel says:

    Has anyone tried a @wire(getRecord, { recordId: ‘$recordId’, FIELDS }) with this? I cant seem to get anything back no errors no data.

    Reply
  6. Thomas
    Thomas says:

    Has anyone run into an issue of defining a property in the XML of a custom class with a namespace.

    But I keep getting is either not supported by ‘lightning__FlowScreen’ or does not exist. when i deploy

    Reply
  7. Scott
    Scott says:

    The LWC Dev Guide suggests that the FlowAttributeChangeEvent should allow us to trigger component visibility logic in a flow screen but having trouble getting other components to show/hide based out outputs of a custom component. Am I reading the docs wrong? Has anyone else been able to get that to work?

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply