Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Screenshot demonstrating a custom Salesforce Flow Counter component enhancing the user experience in a screen flow
LWC

Build a Custom Salesforce Flow Counter LWC for Better UX

Standard number inputs in Screen Flows are a pain on a phone. This guide walks through a custom counter component that makes data entry feel like a modern app.

The short answer

This guide covers building a reusable numeric counter Lightning web component with increment and decrement buttons for Salesforce Screen Flows. It includes the component HTML, CSS, JavaScript, and metadata configuration, plus wiring the input and output variables in Flow Builder.

Key takeaways Set the component target to lightning__FlowScreen in the metadata configuration file, or the LWC never shows up in Flow Builder. Declare the component properties with the @api decorator so inputs and outputs pass between the Screen Flow and the LWC. Dispatch a change event in JavaScript every time the counter value updates, so the Flow runtime sees the new value. Spell the flow input variable recordId with exactly that casing, or Quick Actions will not pass the record ID automatically.

Ever had a user complain that the standard number input in a Screen Flow feels clunky? I get it. A simple Salesforce Flow Counter LWC is often all it takes to make a screen feel like a modern app instead of a database form, and it is one of those small UX wins that makes people enjoy using the tools we build.

In my experience, users hate typing if they don't have to. Out in a warehouse or on a retail floor, they want big, clickable buttons. This guide shows you how to build a reusable counter component you can drop into any flow so users tap their way to the right number.

Why you need a Salesforce Flow Counter LWC for better UX

The standard number field in a flow works, but it gives users no tactile feedback. When I first worked with inventory management apps, store managers were constantly fat-fingering numbers on their mobile devices. A plus-minus counter fixes that.

A custom Salesforce Flow Counter LWC gives them a clean interface for inventory adjustments, quantity picks, or simple numeric scores. It cuts errors because they watch the value change in real time instead of clicking into a tiny text box, and it is reusable across objects and flows.

UI mockup of a Salesforce Screen Flow with a custom numeric counter component and its increment and decrement buttons.

The counter as users see it: a label, the current value, and a button on each side.

Step 1: Prep your custom field

Before we touch any code, you need a place to store the data. For this example we'll use the Product object. Create a Number field on Product2. I usually call it "Current Inventory" or something similar. Set it to 3 digits with no decimals. Check your field-level security too, so the users running the flow can actually see and edit it.

Step 2: Building the Salesforce Flow Counter LWC

Now the component itself. It has three jobs: show a label, handle the button clicks that change the value, and tell the Flow when that value changes. If you are new to this, read up on LWC component communication first to see how data moves between elements.

screenCounterComponent.html

<template>
    <div class="slds-form-element">
        <label class="slds-form-element__label">{label}</label>
        <div class="slds-form-element__control">
            <div class="slds-grid slds-grid_vertical-align-center">
                <button class="slds-button slds-button_icon slds-button_icon-border" 
                        onclick={decrementCounter}>
                    <lightning-icon icon-name="utility:dash" size="small" class="decrement-color"></lightning-icon>
                </button>
                <input type="number" 
                       class="slds-input slds-m-horizontal_small slds-text-align_center" 
                       value={counterValue} 
                       onchange={handleInputChange} />
                <button class="slds-button slds-button_icon slds-button_icon-border" 
                        onclick={incrementCounter}>
                    <lightning-icon icon-name="utility:add" size="small" class="increment-color"></lightning-icon>
                </button>
            </div>
        </div>
    </div>
</template>

screenCounterComponent.css

.increment-color { - sds-c-icon-color-foreground-default: #2e844a; 
}
.decrement-color { - sds-c-icon-color-foreground-default: #ea001e; 
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

screenCounterComponent.js

This is where the logic lives. The @api decorator lets the Flow talk to our component. When the value changes, we dispatch a "change" event, which is how the Flow learns the new number.

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

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

    @track counterValue;

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

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

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

    handleInputChange(event) {
        this.counterValue = parseInt(event.target.value, 10) || 0;
        this.updateFlowValue();
    }

    updateFlowValue() {
        this.value = this.counterValue;
        this.dispatchEvent(new CustomEvent('change'));
    }
}

screenCounterComponent.js-meta.xml

This part is critical. If you don't set the target to lightning__FlowScreen, your component never appears in the Flow builder. The inputs and outputs are defined here too.

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

Wiring the Salesforce Flow Counter LWC into your Flow

Now that the code is deployed, it is time to use it. Open the Flow Builder and create a new Screen Flow. Start by creating a variable called recordId (Available for Input) so the flow knows which product it is looking at.

  1. Get Records: fetch the Product record where the Id matches your recordId variable.
  2. Screen Element: drag your new "LWC Counter Component" onto the screen. Set the "Label" to something like "Adjust Stock" and map the "Starting Value" to the current inventory field from your Get Records element.
  3. Update Records: use the output value from the LWC to update the Product record.

Spell that recordId variable exactly: lowercase "r", uppercase "I". Get it wrong and the Quick Action won't pass the ID automatically, and you'll sit there wondering why the flow is blank.

If you enjoy building custom UI like this, there's also my tutorial on how to build a reusable Salesforce Flow progress bar with LWC. It uses similar logic to keep users engaged during long processes.

Key takeaways

  • A Salesforce Flow Counter LWC improves mobile usability by replacing small text inputs with large, clickable buttons.
  • The @api decorator is how you pass data between the Flow and your LWC.
  • Always include a "change" event in your JS so the Flow engine knows the value changed before the user clicks "Next".
  • CSS custom properties (SLDS hooks) are the easiest way to color your icons without writing complex styles.

Wrap up

For the org, this shows up as fewer support tickets about "bad data" and a happier user base. A component like this makes the system work for the people using it every day. Try it in a sandbox and watch how much faster your users get through their tasks.

Frequently asked questions

How do you make an LWC available in Salesforce Screen Flow?

Set isExposed to true and add lightning__FlowScreen to the targets section of the component's js-meta.xml file. Input and output properties go in targetConfig.

How do you pass data from an LWC to a Screen Flow?

Declare an @api property in the JavaScript file and expose it as a property in the js-meta.xml file. When the value changes in the component, update the property and dispatch a change event.

Why is the recordId variable blank when running a Screen Flow from a Quick Action?

The variable has to be set as Available for Input and spelled exactly as recordId, lowercase r and uppercase I. Any other casing stops Salesforce Quick Actions from passing the record ID automatically.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment