Skip to main content

The Percent Field Display Gotcha in Lightning Web Components

One of the most common and confusing display bugs in LWC development involves percent fields showing values 100 times larger than expected. A field that should display as 2% instead shows as 200%. This article explains the root cause and the fix.

The Symptom

You query a record with a percent field and display it using lightning-formatted-number:

<lightning-formatted-number
value={record.Markup_Percent__c}
style="percent"
minimum-fraction-digits="2"
></lightning-formatted-number>

The field in Salesforce shows 2.00%, but your component renders 200.00%.

The Root Cause

There is a mismatch between how Salesforce stores percent values and how the lightning-formatted-number component with style="percent" expects them.

Salesforce storage format: Percent fields are stored as whole numbers. A value of 2% is stored as 2 in the database and returned as 2 from Apex queries and wire adapters.

lightning-formatted-number expectation: When style="percent" is set, the component follows the JavaScript Intl.NumberFormat convention, which expects a decimal fraction. To display 2%, it expects the input value 0.02. It then multiplies by 100 internally for display.

The result: passing 2 (the Salesforce storage value) to a percent-styled formatter produces 2 * 100 = 200%.

The Fix

Divide the Salesforce value by 100 before passing it to the formatter.

Option 1: Getter in the JavaScript Controller

get markupPercentDecimal() {
if (this.record?.Markup_Percent__c == null) return null;
return this.record.Markup_Percent__c / 100;
}
<lightning-formatted-number
value={markupPercentDecimal}
style="percent"
minimum-fraction-digits="2"
></lightning-formatted-number>

Option 2: Transform During Data Processing

When you process records into a display-ready format (common in table components), apply the conversion at that stage:

get displayItems() {
return this.items.map((item) => ({
...item,
markupForDisplay: item.Markup_Percent__c != null
? item.Markup_Percent__c / 100
: null,
}));
}

When NOT to Convert

If you are displaying the value as a plain number (without style="percent"), do not divide by 100. The raw value is correct for numeric display:

<!-- This correctly shows "2" -->
<lightning-formatted-number
value={record.Markup_Percent__c}
></lightning-formatted-number>

<!-- Append the percent sign manually if needed -->
<span>{record.Markup_Percent__c}%</span>

The conversion is only necessary when using style="percent", which triggers the Intl.NumberFormat percent formatting behavior.

Where to Apply the Conversion

Apply the division in the JavaScript controller, not in the template. LWC templates do not support arithmetic expressions, so you cannot write value={record.Markup_Percent__c / 100} inline. This is by design -- LWC encourages moving logic into the controller.

For components that display many percent fields, a utility function keeps things consistent:

// percentUtils.js (shared utility module)
export function toDisplayPercent(value) {
return value != null ? value / 100 : null;
}
// In your component
import { toDisplayPercent } from "c/percentUtils";

get markupForDisplay() {
return toDisplayPercent(this.record.Markup_Percent__c);
}

Testing the Fix

Verify with boundary values:

Salesforce ValueAfter DivisionDisplayed As
000.00%
20.022.00%
1001100.00%
0.50.0050.50%
nullnull(empty)

This gotcha affects every Salesforce percent field displayed with lightning-formatted-number using percent style. Once you know the pattern, it becomes a quick check during code review: if you see style="percent", confirm the value is being divided by 100.