Flow Screen Component LWC – How to Maintain Internal State on Page Navigation or Validation Error

flow-screen-componentlightning-web-componentsscreen-flowvisual-workflow

Problem

When creating a LWC FSC, the internal state of the LWC is reset when the user navigates to another page and back, or attempts to navigate to another page but is kept on the same page due to a validation error (e.g. a required field is missing a value)

This results in the LWC losing the information provided by the user, and the user then needs to re-enter that information.

In the Demo below, if I provide a variable for the input parameters into my LWC FSC, the state of that variable is maintained. The problem is, I don't want to expose all internal variables as an input/output of the flow. In this demo, I don't want to pass in category. I don't want category to be defined as an input or output.

Question

Is there a way to maintain the state of an LWC, without the flow itself needing to pass the data into it?

Demo

(this isn't the best example, but the simplest I could think of)

My LWC helps the user select a fruit/vegetable from a grocery picker. The fruit/veg is the output, and there is a category of fruit or veg.

html

<template>

    <lightning-combobox
        name="category"
        label="Category"
        value={category}
        options={categoryOptions}
        required="true"
        onchange={handleCategoryChange} >
    </lightning-combobox>

    <lightning-combobox
        name="item"
        label="Item"
        value={item}
        options={itemOptions}
        required="true"
        onchange={handleItemChange} >
    </lightning-combobox>

</template>

js

import { LightningElement, api } from 'lwc';

const GROCERIES = {
    fruit: ['banana', 'apple', 'orange'],
    vege:  ['cabbage', 'lettuce', 'carrot']
};

export default class GroceryPicker extends LightningElement {
    @api category;
    @api item;

    get categoryOptions() {
        return Object.keys(GROCERIES).map( element => {
            return {
                label: element,
                value: element
            }
        })
    }

    get itemOptions() {
        return this.category && GROCERIES[this.category].map( element => {
            return {
                label: element,
                value: element
            }
        })
    }

    handleCategoryChange(event) {
        this.category = event.target.value;
    }

    handleItemChange(event)  {
        this.item = event.target.value;
    }
}

config

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>53.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__FlowScreen</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__FlowScreen">
            <property name="item"
                type="String"
                label="Item"
                required="false"
            />
            <property name="category"
                type="String"
                label="Category"
                required="false"
            />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Setup in the flow

Note the item and category don't have an input value

enter image description here

Before clicking next

enter image description here

After clicking next

When clicking next, the flow leaves us on the same page due to the required text field failing validation. The category/item are cleared.

enter image description here

Update FSC to pass in item/category

Set the LWC FSC inputs. myItem and myCategory are flow text variables without any value.

enter image description here

Now item/category values are retained when clicking next, even though there's a validation error.

enter image description here

Best Answer

It seems you know the way to actually do this - setting the variables as input/output and passing it in and storing output in the Flow setup. Considering the LWC is re-initialized when going back to the screen (or in the case of validation error) - it needs values passed in for your situation.


So if you don't want to use the mechanism provided with Flow/LWC, you'd have to leverage another mechanism - something like browser sessionStorage to store/retrieve values.

export default class GroceryPicker extends LightningElement {
    @api category;
    @api item;

    //set existing selected value by user 
    connectedCallback(){
        this.categoryOptions = //set category options 
        //check if there's a cached selection by this user
        let cachedSelection= sessionStorage.getItem(this.sessionStorageKey);
        if(cachedSelection && this.validateSessionStorageValue(cachedSelection){
            this.category = cachedSelection;
        }
    }

    handleCategoryChange(event) {
        this.category = event.target.value;
        //set the value in session storage to retrieve, if needed, later
        sessionStorage.setItem(this.sessionStorageKey, event.target.value);
    }

    get sessionStorageKey() {
        //create some sort of unique key - add any relevant variables for flow (recordId) to make it unique per user (can pull userId)
        return 'groceryPickerCategory.${this.userId}';
        
    }
    
    validateSessionStorageValue(retrievedValue) {
        this.categoryOptions.forEach(option => {
            if(option.value === retrievedValue){
                return true;
            }
        }
        return false;
    }
}

Considerations

  • Only showed an example for categories based on your question
  • You'll probably want to validate the value you pull from session storage against your list of valid values
  • If the user quits the flow screen - the value is saved. That may or may not be desirable behavior to have it autofill if they click it again.
Related Topic