Intl.NumberFormat

Published · tagged with Intl

You might already be familiar with the Intl.NumberFormat API, as it’s been supported across modern environments for a while now.

  • Babel: supported
  • Chrome: supported since version 24
  • Firefox: supported since version 29
  • Node.js: supported since version 0.12
  • Safari: supported since version 10

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 Numbers, Intl.NumberFormat can now also format BigInts:

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' }
// → ]

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'
  • Babel: no support
  • Chrome: supported since version 77
  • Firefox: no support
  • Node.js: no support
  • Safari: 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'
  • Babel: no support
  • Chrome: supported since version 77
  • Firefox: no support
  • Node.js: no support
  • Safari: 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)'
  • Babel: no support
  • Chrome: supported since version 77
  • Firefox: no support
  • Node.js: no support
  • Safari: 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.