Screen Flows, part of Salesforce Flow, lets developers and administrators create user interfaces and tie them to Salesforce data using code or no-code tools. Screen flows allow developers to use Lightning Web Components (LWC) as flow elements. However, building LWCs for a flow requires that you follow some best practices. Doing so increases the performance of your LWCs, and your component works better within the Flow runtime engine.
In this blog, we first dive into how state management works in the Flow runtime, and then share some state management and event best practices that you should follow when building LWCs for your screen flows.
Best practices for LWC state management in screen flows
The Flow runtime adheres to LWC state management design principles. It works best when the LWC components that it renders do not modify their own @api
attributes and instead request that a change be made by firing FlowAttributeChangeEvents
.
This pattern is essential for two reasons.
- Components that allow their parents to control their
@api
parameters are more easily reused because they allow the application to control the state rather than the component’s own internal business logic. - By firing attribute change events, the Flow runtime can maintain an accurate picture of the component state, which allows it to control inter-component interactions, such as conditional field visibility.
Using Salesforce LWC’s linter rules is an excellent way to ensure that your component does not modify @api
parameters. Set up a linter that uses LWC’s linter rules in your development environment, specifically ensuring that the lwc/no-api-reassignments setting is enforced.
Below is an example of a simple text input component. It demonstrates how a FlowAttributeChangeEvent
should be fired in lieu of updating the LWC’s @api
parameter.
Troublesome code
Compliant code
Best practices for LWC events in screen flows
In the upcoming sections, we deep dive into best practices for flow events like FlowAttributeChangeEvent
and FlowNavigationEvent
.
Attribute change event best practices
This section presents a list of FlowAttributeChangeEvent
(see docs) Dos and Don’ts.
- Do not modify
@api
attributes in the component. Instead, fire theFlowAttributeChangeEvents
event. - Do fire the event in event handlers or in methods invoked within event handlers.
- Do limit the event’s value parameter to the following data types:
- String
- Number
- Boolean
- JSON (for record types)
- Do ensure that the data type of the
FlowAttributeChangeEvent
value parameter matches the data type of the LWC’s@api
parameter. - Do react to changes to
@api
parameters by using aget/set
pattern where appropriate. This is also needed to cross-communicate between components when you are using reactive screen components (Beta).
The example below demonstrates using get/set
to count the updates to an @api
parameter vs. simply incrementing a counter before firing an attribute change event. It is worth noting that both the below patterns are valid but achieve slightly different results.
In the above scenario, this.changeCounter
will be incremented whenever the user inputs a change in the text input and whenever the Flow runtime determines that the textValue
property has changed. This will consider component initialization and cross-component interactions when using reactive screen components.
Note: an intermediate variable will need to be used to render updates from the set method. In this example, we introduce the
textValueToRender
for this purpose.
Let’s look at a code example where we increment a counter before firing an attribute change event. In this scenario, we do not use the get/set
pattern.
In this case, this.changeCounter
will be incremented whenever the user inputs a change in the text input.
6. Do use anotationless or @track
parameters to maintain a modifiable local component state.
The example below shows a color picker that presents the user with an input text box and some swatches. Note that the color picker component returns color to the flow, so only color
needs to be an @api
parameter, the selectedSwatchId
and inputValue
members are internal only and hence do not need any decorator.
colorPicker.js
7. Do use a get
method to combine multiple @api
parameters together to construct a derived variable for the view.
Salutation.js
8. Do apply the same logic in the set
method of every @api
parameter that contributes to a derived member variable. This is needed for internal component state management for complex scenarios. This will ensure that a change made to any contributing attribute will cause the value to render correctly, regardless of the order in which attributes are set.
Dropdown.js
9. Do not modify FlowAttributeChangeEvent
parameters after construction. By default, FlowAttributeChangeEvent
instances are composed and bubble.
10. Avoid firing FlowAttributeChangeEvents
and FlowNavigationXxx
events at the same time. The rationale for this is it can lead to race conditions. There’s never a guarantee that the LWC component has had time to render the updated values by the time we start the navigation process.
Navigation change event best practices
In addition to the FlowAttributeChangeEvent
, custom LWCs can fire navigation events to move between screens and pause or finish flows.
The intent of navigation events is to allow for custom LWC authors to include additional control mechanisms within their components. To that end, navigation events should be fired when reacting to end-user interaction.
Consult the list of Dos and Don’ts below when planning on using navigation events.
- Do fire navigation events in event handlers (or in the method they invoke).
- Do not fire navigation events outside of event handlers as it leads to a poor experience for the end user.
- Do not fire navigation events in lifecycle handlers like
renderedCallback
andconnectedCallback
.
The logic for skipping screens should rest in Flow Decision Nodes and should not be determined during the lifecycle of a screen. Additionally, navigation in a dummy screen can lead to poor flow performance.
Conclusion
We love it when developers create innovative solutions with Lightning Web Components combined with Flows. Following the best practices outlined in this blog ensures that your components integrate well within the Flow runtime engine and work as expected.
References
- Component reference for
flow-support
- Flow runtime considerations
About the authors
Josh Goodman is a Principal Member of the Technical Staff with over 7 years of experience as a developer at Salesforce. Through his tenure, Josh has worked on many exciting features such as adding Reports and Dashboards to Salesforce One mobile, bringing Wave Charting to Lightning, adding nested folder support to the Reports and Dashboard home pages, and converting the Flow UI to from Aura to LWC. He is currently working on exciting new UI runtime features for Flows.
Mohith Shrivastava is a Developer Advocate at Salesforce with a decade of experience building enterprise-scale products on the Salesforce Platform. He is presently focusing on the Salesforce Developer Tools, Flow, Apex, and Lightning Web Components at Salesforce. Mohith is currently among the lead contributors on Salesforce Stack Exchange, a developer forum where Salesforce Developers can ask questions and share knowledge. You can follow him via his Twitter @msrivastav13.