Best Practices for Reactivity in Screen Flows (Beta)

Ensure your Lightning web components integrate well within the Flow runtime engine and work as expected for Screen Flow reactivity.

These sections describe state management with reactivity in Screen Flows, including:

  • How LWC state management differs from Aura
  • How state management works in the new LWC Flow Runtime
  • State management and event best practices to follow when building LWCs for your screen flows

State management for Aura components and LWCs follow different paradigms. In Aura components, <aura:attributes /> are viewed and modified by the component to which they belong, including external components. LWCs are designed to have a clear separation between internal and external states. Variables declared with @api are intended to be modified only by the LWC’s parents. Variables without the @api annotation and variables with @track are considered internal states and can be changed within the LWC that defines them.

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. Instead, components request a change by firing FlowAttributeChangeEvent, which is essential for several reasons.

  • Components that allow their parents to control their @api properties 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 maintains an accurate picture of the component state. The Flow runtime can control inter-component interactions such as conditional field visibility, which is part of reactivity.

Using LWC linter rules is an excellent way to ensure that your component does not modify @api properties. Set up a linter that uses LWC’s linter rules in your development environment, specifically ensuring that the setting is enforced.

To maintain consistent behavior between Flow Runtime versions, when a user clicks the Next or Finish button, the Flow Runtime collects values by extracting each custom LWC component’s current @api attribute state before moving to the next screen or finishing the flow. This mechanism ensures that components that do not adhere to the prescribed design pattern continue to work in the latest Flow Runtime version. It is strongly recommended to avoid relying on this behavior.

Here is an example of a simple text input component that demonstrates firing FlowAttributeChangeEvent instead of updating the LWC’s @api property:

The following example isn’t recommended.

The FlowAttributeChangeEvent event provides LWCs the ability to inform the runtime of their current state. It is part of Flow Runtime’s state management mechanism. These events are meant to be fired whenever user interaction results in a modification that requires an update to an @api property.

Import FlowAttributeChangeEvent from the lightning/flowSupport module.

Next, you can create an instance of the event.

FlowAttributeChangeEvent includes two arguments.

  • apiParameterName—The name of the API property to modify.
  • updatedValue—The updated value for the Flow attribute.

Pass a string to apiParameterName that matches the API property as it appears in the JavaScript and .js-meta.xml files.

For example, notice how exampleApiParameterName is consistent in all 3 places:

  • Declare the attribute in the LWC’s .js-meta.xml file:

  • Declare the API property in the LWC’s .js file:

  • Construct the FlowAttributeChangeEvent instance:

Pass the updatedValue to match the declared datatype in the .js-meta.xml file.

  • Declare the property as a Record:

  • Declare the property as a string:

  • Declare the property as a number:

  • Declare the property as a boolean:

After constructing a FlowAttributeChangeEvent instance, you can fire the event using the this.dispatchEvent(eventToFire) method.

Follow these FlowAttributeChangeEvent examples and steer clear of problematic usages to reduce unexpected behaviors after a flow version upgrade. These best practices enable you to maintain your components more easily.

  • Fire events in event handlers or in methods invoked within event handlers.
  • Limit an event’s value parameter to the following datatypes: String, number, boolean, JSON (for record types).
  • Ensure that the Flow datatype of the event’s value parameter matches the datatype of the LWC’s @api property.
  • React to changes to @api properties by using a get/set pattern where appropriate.

This example demonstrates using a getter and setter to count the updates with an @api property vs. incrementing a counter before firing an attribute change event. Both patterns are valid, but they achieve slightly different results.

In this case, this.changeCounter is incremented whenever the user enters a change in the text input and whenever the Flow Runtime determines that the textValue property has changed. This approach accounts for component initialization and cross-component interactions via reactivity. Use an intermediate variable to render updates from the set method. In this example, textValueToRender fills this role.

The following code example increments a counter before firing an attribute change event. This scenario doesn’t use the get/set pattern.

In this case, this.changeCounter is incremented whenever the user inputs a change in the text input. The counter does not update when reactivity changes the value of this field.

Use annotationless or @track properties to maintain a modifiable local component state.

The following example shows a color picker that presents the user with an input text box and some swatches. The color picker component returns color to the flow, so only color needs the @api annotation. The selectedSwatchId and inputValue members are internal only and do not need any decorator.

Use a get method to combine multiple @api properties together to construct a derived variable for the view.

Apply the same logic in the set method of every @api property that contributes to a derived member variable needed for internal component state management, as in more complex scenarios than the previous example. This logic ensures that a change made to any contributing attribute causes the value to render correctly regardless of the order of the set attributes.

Don’t modify @api properties. Fire FlowAttributeChangeEvents instead.

Don’t modify FlowAttributeChangeEvent parameters after construction. By default, FlowAttributeChangeEvent instances are composed and bubble.

Avoid firing FlowAttributeChangeEvents and FlowNavigationXxx events at the same time as it can lead to race conditions. There's never a guarantee that your Lightning web component has had time to render the updated values by the time the navigation process is started.

In addition to FlowAttributeChangeEvent, your Lightning web components can fire navigation events to move between screens, pause, or finish flows. To work with navigation events, import these functions from lightning/flowSupport:

  • FlowNavigationNextEvent
  • FlowNavigationBackEvent
  • FlowNavigationPauseEvent
  • FlowNavigationFinishEvent

This snippet describes how to import and fire a navigation event. While the example uses FlowNavigationNextEvent, the same structure holds for each of the available navigation targets.

Navigation events allow your Lightning web components to include additional control mechanisms. Fire navigation events when reacting to end-user interactions. Refer to these guidelines when using navigation events:

  • Fire navigation events in event handlers (or in the method they invoke).
  • Don’t fire navigation events outside of event handlers because it leads to a poor user experience.
  • Don’t fire navigation events in lifecycle handlers like renderedCallback and connectedCallback.
  • Place the logic for skipping screens in Flow Decision Nodes, not in the lifecycle of a screen.
  • Don’t perform navigation in a dummy screen because it can lead to poor Flow performance.
  • If you encounter a scenario where navigation must be done within the initialization phase of the screen because data isn’t yet available to Flow Decision Nodes, post a request for an upgrade in Idea Exchange