You might already be familiar with the Intl.NumberFormat
API, as it’s been supported across modern environments for a while now.
- Chrome: supported since version 24
- Firefox: supported since version 29
- Safari: supported since version 10
- Node.js: supported since version 0.12
- Babel: supported
In its most basic form, Intl.NumberFormat
lets you create a reusable formatter instance that supports locale-aware number formatting. Just like other Intl.*Format
APIs, a formatter instance supports both a format
and a formatToParts
method:
const formatter = new Intl.NumberFormat('en');
formatter.format(987654.321);
// → '987,654.321'
formatter.formatToParts(987654.321);
// → [
// → { type: 'integer', value: '987' },
// → { type: 'group', value: ',' },
// → { type: 'integer', value: '654' },
// → { type: 'decimal', value: '.' },
// → { type: 'fraction', value: '321' }
// → ]
Note: Although much of the Intl.NumberFormat
functionality can be achieved using Number.prototype.toLocaleString
, Intl.NumberFormat
is often the better choice, since it enables creating a re-usable formatter instance which tends to be more efficient.
Recently, the Intl.NumberFormat
API gained some new capabilities.
BigInt
support #
In addition to Number
s, Intl.NumberFormat
can now also format BigInt
s:
const formatter = new Intl.NumberFormat('fr');
formatter.format(12345678901234567890n);
// → '12 345 678 901 234 567 890'
formatter.formatToParts(123456n);
// → [
// → { type: 'integer', value: '123' },
// → { type: 'group', value: ' ' },
// → { type: 'integer', value: '456' }
// → ]
- Chrome: supported since version 76
- Firefox: no support
- Safari: no support
- Node.js: no support
- Babel: no support
Units of measurement #
Intl.NumberFormat
currently supports the following so-called simple units:
- angle:
degree
- area:
acre
,hectare
- concentration:
percent
- digital:
bit
,byte
,kilobit
,kilobyte
,megabit
,megabyte
,gigabit
,gigabyte
,terabit
,terabyte
,petabyte
- duration:
millisecond
,second
,minute
,hour
,day
,week
,month
,year
- length:
millimeter
,centimeter
,meter
,kilometer
,inch
,foot
,yard
,mile
,mile-scandinavian
- mass:
gram
,kilogram
,ounce
,pound
,stone
- temperature:
celsius
,fahrenheit
- volume:
liter
,milliliter
,gallon
,fluid-ounce
To format numbers with localized units, use the style
and unit
options:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'kilobyte',
});
formatter.format(1.234);
// → '1.234 kB'
formatter.format(123.4);
// → '123.4 kB'
Note that over time, support for more units may be added. Please refer to the spec for the latest up-to-date list.
The above simple units can be combined into arbitrary numerator and denominator pairs to express compound units such as “liters per acre” or “meters per second”:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'meter-per-second',
});
formatter.format(299792458);
// → '299,792,458 m/s'
- Chrome: supported since version 77
- Firefox: no support
- Safari: no support
- Node.js: no support
- Babel: no support
Compact, scientific, and engineering notation #
Compact notation uses locale-specific symbols to represent large numbers. It is a more human-friendly alternative to scientific notation:
{
// Test standard notation.
const formatter = new Intl.NumberFormat('en', {
notation: 'standard', // This is the implied default.
});
formatter.format(1234.56);
// → '1,234.56'
formatter.format(123456);
// → '123,456'
formatter.format(123456789);
// → '123,456,789'
}
{
// Test compact notation.
const formatter = new Intl.NumberFormat('en', {
notation: 'compact',
});
formatter.format(1234.56);
// → '1.2K'
formatter.format(123456);
// → '123K'
formatter.format(123456789);
// → '123M'
}
Note: By default, compact notation rounds to the nearest integer, but always keeps 2 significant digits. You can set any of {minimum,maximum}FractionDigits
or {minimum,maximum}SignificantDigits
to override that behavior.
Intl.NumberFormat
can also format numbers in scientific notation:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'meter-per-second',
notation: 'scientific',
});
formatter.format(299792458);
// → '2.998E8 m/s'
Engineering notation is supported as well:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'meter-per-second',
notation: 'engineering',
});
formatter.format(299792458);
// → '299.792E6 m/s'
- Chrome: supported since version 77
- Firefox: no support
- Safari: no support
- Node.js: no support
- Babel: no support
Sign display #
In certain situations (such as presenting deltas) it helps to explicitly display the sign, even when the number is positive. The new signDisplay
option enables this:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'percent',
signDisplay: 'always',
});
formatter.format(-12.34);
// → '-12.34%'
formatter.format(12.34);
// → '+12.34%'
formatter.format(0);
// → '+0%'
formatter.format(-0);
// → '-0%'
To prevent showing the sign when the value is 0
, use signDisplay: 'exceptZero'
:
const formatter = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'percent',
signDisplay: 'exceptZero',
});
formatter.format(-12.34);
// → '-12.34%'
formatter.format(12.34);
// → '+12.34%'
formatter.format(0);
// → '0%'
// Note: -0 still displays with a sign, as you’d expect:
formatter.format(-0);
// → '-0%'
For currency, the currencySign
option enables the accounting format, which enables a locale-specific format for negative currency amounts; for example, wrapping the amount in parentheses:
const formatter = new Intl.NumberFormat('en', {
style: 'currency',
currency: 'USD',
signDisplay: 'exceptZero',
currencySign: 'accounting',
});
formatter.format(-12.34);
// → '($12.34)'
formatter.format(12.34);
// → '+$12.34'
formatter.format(0);
// → '$0.00'
formatter.format(-0);
// → '($0.00)'
- Chrome: supported since version 77
- Firefox: no support
- Safari: no support
- Node.js: no support
- Babel: no support
More info #
The relevant spec proposal has more information and examples, including guidance on how to feature-detect each individual Intl.NumberFormat
feature.