Elevate Screen Flows with a Customizable Counter LWC: Step-by-Step Guide

Add an accessible, reusable Lightning Web Component counter to your Salesforce Screen Flows to let users increment/decrement numeric values and pass them back to flows. This guide walks through building the LWC, wiring it to a Screen Flow, and deploying via a quick action.

Overview

This article shows how to build a customizable Counter component using Lightning Web Components (LWC) and use it inside a Salesforce Screen Flow. The component provides increment/decrement buttons, editable numeric input, and a clean UX for scenarios like inventory adjustments, quantity selection, or quick numeric edits.

Business use case

Imagine store managers performing inventory audits and needing a fast, reliable way to adjust product stock directly from a product record. A Counter component embedded in a Screen Flow launched via a Quick Action reduces clicks, prevents manual errors, and improves user satisfaction.

What you will build

  • A reusable LWC Counter that exposes input properties and returns the selected value to a flow.
  • A Screen Flow that retrieves the Product record, shows the counter, updates the product stock level, and confirms the change.
  • A Quick Action on the Product record to launch the flow and pass the record Id.

Step 1 — Add a custom field to store inventory

Create a Number field (Length: 3, Decimal Places: 0) on Product2, add help text and field-level security, and include it on the Product page layout. This field will hold the current stock level referenced by the flow.

Step 2 — Build the Counter LWC

Create an LWC bundle set to be exposed to Screen Flows. The example below shows the HTML, CSS, JS, and meta-XML required for a simple but effective counter that sends its value back to the flow via the standard change event.

screenCounterComponent.html

<template>
    <div class="slds-form-element">
        <label class="slds-form-element__label slds-m-right_none" for="state-required">
            <abbr class="slds-required" title="required"*>*</abbr>{label}
        </label>
        <div class="slds-form-element__control">
            <button class="slds-button slds-button_icon slds-button_icon-small slds-input__button_decrement" 
                    title="Decrement counter" 
                    onclick={decrementCounter}>
                <lightning-icon icon-name="utility:ban" size="small" class="decrement-color"></lightning-icon>
                <span class="slds-assistive-text">Decrement counter</span>
            </button>
            <input type="number" id="state-required" 
                   placeholder="1" required 
                   class="slds-input slds-input_counter {counterClass}" 
                   value={counterValue} 
                   onchange={handleInputChange} />
            <button class="slds-button slds-button_icon slds-button_icon-small slds-input__button_increment" 
                    title="Increment counter" 
                    onclick={incrementCounter}>
                <lightning-icon icon-name="utility:new" size="small" class="increment-color"></lightning-icon>
                <span class="slds-assistive-text">Increment counter</span>
            </button>
        </div>
    </div>
</template>

screenCounterComponent.css

.increment-color {
    --sds-c-icon-color-foreground-default: green; 
}

.decrement-color {
    --sds-c-icon-color-foreground-default: red; 
}

screenCounterComponent.js

import { LightningElement, api, track } from 'lwc';

export default class ScreenCounterComponent extends LightningElement {
    @api label;
    @api defaultValue = 0;
    @api value;

    @track counterValue = this.defaultValue;

    connectedCallback() {
        this.counterValue = this.defaultValue;
    }

    incrementCounter() {
        this.counterValue++;
        this.passValueToFlow();
    }

    decrementCounter() {
        if (this.counterValue > 0) {
            this.counterValue--;
            this.passValueToFlow();
        }
    }

    handleInputChange(event) {
        const inputValue = parseInt(event.target.value, 10);
        if (!isNaN(inputValue)) {
            this.counterValue = inputValue;
            this.passValueToFlow();
        }
    }

    passValueToFlow() {
        this.value = this.counterValue;
        const valueChangeEvent = new CustomEvent('change', {
            detail: { value: this.counterValue }
        });
        this.dispatchEvent(valueChangeEvent);
    }
}

screenCounterComponent.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="counterComponent">
    <apiVersion>61.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>LWC Counter Component</masterLabel>
    <description>LWC Counter Component</description>
    <targets>
        <target>lightning__FlowScreen</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__FlowScreen">
            <property name="label" type="String" label="Counter Label" role="inputOnly" />
            <property name="defaultValue" type="Integer" label="Default Value" />
            <property name="value" type="Integer" role="outputOnly" label="Counter Value" />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Step 3 — Build the Screen Flow

High-level flow steps:

  • Define flow properties and create a text variable recordId (Available for Input/Output).
  • Get Product record using a Get Records element and store all fields.
  • Add a Screen element and drop the Counter LWC onto the screen. Bind Default Value to the product stock field.
  • Use an Update Records element to update Product.Current_Stock_Level__c equal to the LWC output value.
  • Add a confirmation screen to display success text with the new value.

Step 4 — Quick Action to launch the Flow

Create a new Action on the Product2 object, set the Action Type to Flow and select the flow you built. Add the Quick Action to the Product record page so users can launch the Screen Flow directly from a product record.

Best practices and considerations

  • Validate min/max values in the LWC as needed to prevent invalid stock levels.
  • Consider permission checks in the flow to ensure only authorized users can change inventory.
  • Use descriptive labels and assistive text for accessibility.
  • Test the flow with different profiles and record types before enabling for all users.

Why this matters

Embedding a clean, focused numeric counter inside Screen Flows reduces friction for end users, speeds up routine updates like inventory adjustments, and minimizes data entry errors. For admins and developers, the pattern creates a reusable component that can be dropped into many flows where numeric input is required.

For Salesforce admins, developers, and business users: this approach delivers a compact, user-friendly interaction that improves operational efficiency and user adoption of automated processes.