Number.prototype.toLocaleString()
Formats a number using locale conventions for grouping, decimals, currency and percent.
toLocaleString()
toLocaleString(locales)
toLocaleString(locales, options)Parameters
| Parameter | Type | Description |
|---|---|---|
$localesoptional | string | string[] | A BCP 47 language tag, or an array of them. Matches the locales parameter of the Intl.NumberFormat() constructor. Ignored where Intl.NumberFormat is unsupported, in which case the host locale is used. |
$optionsoptional | object | An object adjusting the output format, matching the options parameter of the Intl.NumberFormat() constructor — style, currency, minimumFractionDigits, notation and the rest. Ignored where Intl.NumberFormat is unsupported. |
Return value
stringA string representing the number according to language-specific conventions. Where Intl.NumberFormat is available this equals `new Intl.NumberFormat(locales, options).format(number)`.
Errors
Throws a RangeError for an invalid locale tag or an out-of-range option value, following the Intl.NumberFormat() constructor.
This is the method to reach for whenever a number is going to be read by a person. It inserts the grouping separator, uses the right decimal mark, and — with options — handles currency, percentages and compact notation without any string surgery on your part.
Always pass a locale
With no arguments the output depends on whoever is running the code. The same call gives "1,234,567.891" in en-US and "1.234.567,891" in de-DE. Snapshot tests, fixtures and any value you plan to parse back need an explicit tag such as 'en-US'; leave it out only when you genuinely want the user's own convention.
Useful options
{ style: 'currency', currency: 'USD' }— adds the symbol and the correct number of minor digits for that currency.{ style: 'percent' }— multiplies by 100 and appends the sign, so pass0.256, not25.6.{ notation: 'compact' }—"1.2M".{ maximumFractionDigits: 2 }— like toFixed() but with grouping and without forced trailing zeros.
Performance
Each call builds a formatter. In a loop or a table render, construct one Intl.NumberFormat up front and reuse its format() method instead.
Example
When to use it
- Render a price with the right symbol and decimal count for a market
- Show a large count as "1.2M" in a dashboard tile
- Format a ratio as a percentage without manual multiplication
Frequently asked questions
How do I add commas to a number in JavaScript?
Call n.toLocaleString('en-US'), which inserts the grouping separators for that locale. Pin the locale rather than calling with no arguments, since other locales group with periods or spaces.
Why does my percent come out 100 times too large?
style: 'percent' multiplies the value by 100 itself, so pass the ratio (0.256) rather than the already-scaled number (25.6).
Is toLocaleString() slow in a loop?
Each call creates a new formatter, so for many values create one Intl.NumberFormat with the same locale and options and call its format() method instead.
More examples
Compact notation for dashboards
Compact notation picks the right suffix per locale and rounds sensibly, replacing the usual hand-rolled divide-by-1000 ladder.
const counts = [999, 1234, 1234567, 9876543210];
for (const c of counts) {
console.log(c.toLocaleString('en-US', { notation: 'compact' }));
}
// "999"
// "1.2K"
// "1.2M"
// "9.9B"Reusing a formatter in a loop
toLocaleString() constructs a formatter on every call; hoisting one Intl.NumberFormat and calling format() gives identical output and avoids repeating that setup per row.
const fmt = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR',
});
const rows = [12.5, 1999, 0.99];
for (const r of rows) {
console.log(fmt.format(r));
}
// "€12.50"
// "€1,999.00"
// "€0.99"Controlling fraction digits
The fraction-digit options give toFixed()-style control while keeping the grouping separator, which toFixed() never adds.
const v = 1234.5678;
console.log(v.toLocaleString('en-US', { maximumFractionDigits: 2 })); // "1,234.57"
console.log(v.toLocaleString('en-US', { minimumFractionDigits: 6 })); // "1,234.567800"
console.log((5).toLocaleString('en-US', { minimumFractionDigits: 2 })); // "5.00"
console.log(v.toFixed(2)); // "1234.57" — no grouping
Discussion