Formatting Numbers in JavaScript with Intl.NumberFormat

sudo_kaizen profile image Orim Dominic Adah Updated on ・4 min read

According to the documentation on MDN,

The Intl.NumberFormat object is a constructor for objects that enable language-sensitive number formatting

And this means what in practice?

It simply means that with Intl.NumberFormat, JavaScript can construct an object that will have the ability to style (or to be technically correct, format) numbers based on human languages. In other words, numbers can be styled in a more human-understandable format.

Instead of numbers being presented as bland as 1234 or 4561254, numbers can be better presented as 1,234 or $4,561.254. You get the gist? Good!

How does this work? Well, the syntax is simple.

const formatterObject = new Intl.NumberFormat([locales[, options]]);

What the syntax above means is this:

  • formatterObject is the object constructed (created) by Intl.NumberFormat. formatterObject holds methods that can be used to format numbers,
  • locales represents the code for human language that we want to format the number in. And why is this important?

Different languages have different ways of displaying numbers. A number like 123456 will be displayed in Spanish as 123.456, in English as 123,456 and in the Indian numerical system as 1,23,456. localesis a code in the form of a string that informs formatterObject of which language to use when formatting.

You can find a list of the locales under subtag
here. Examples are 'hi' for Hindi, 'de-AT' for German (de) used in Austria (AT) and 'en-IN' for English (en) used in India (IN). Number system codes such as "arab", "arabext" and "latn"

  • options refers to additional configurations that can be used to configure how formatterObject styles numbers. options is an object.

Don't be dismayed by the square braces [] in the syntax. They are simply saying Hey developer! Whatever is within me is optional. You can decide to exclude them when writing the syntax and the default configurations will be used.

Using the number 1234567890.1234 as an example, lets convert our knowledge into code.

const num = 1234567890.1234;

// setup formatters
const hindiNumberFormatter = new Intl.NumberFormat("en-IN");
const britishNumberFormatter = new Intl.NumberFormat("en-GB");
const spanishNumberFormatter = new Intl.NumberFormat("es-ES");

// use formatters
console.log(hindiNumberFormatter.format(num)); // 1,23,45,67,890.123
console.log(britishNumberFormatter.format(num)); // 1,234,567,890.123
console.log(spanishNumberFormatter.format(num)); // 1.234.567.890,123

What happened?

We created three types of number formatters with Intl.NumberFormat: hindiNumberFormatter, britishNumberFormatter and spanishNumberFormatter. Each formatter was created with a locale configuration that sets the formatting language of the formatter.

Next, we use the format method on the formatters to style the number num and display the result on the console.

And why is the last 4 not displayed in the formatted result? Did you notice that? Okay. Lets try another example:

const num = 1234567890.1234;
const formatConfig = {
  style: "currency",
  currency: "USD", // CNY for Chinese Yen, EUR for Euro
  minimumFractionDigits: 2,
  currencyDisplay: "symbol",

// setup formatters
const britishNumberFormatter = new Intl.NumberFormat("en-GB", formatConfig);
const spanishNumberFormatter = new Intl.NumberFormat("es-ES", formatConfig);

// use formatters
console.log(britishNumberFormatter.format(num)); // US$1,234,567,890.12
console.log(spanishNumberFormatter.format(num)); // 1.234.567.890,12 US$

😃 Interesting! What happened here again?

Remember the second parameter in the Intl.NumberFormat? The options object? It is used to setup additional configurations for how formatterObject would format numbers passed to it. With properties such as style (possible values are "decimal" for plain number formatting, "currency" for currency formatting, and "percent" for percent formatting; the default is "decimal"), currency, maximumSignificantDigits (values are integers that determine how many significant digits the number to be formatted should have), minimumFractionDigits (having the value of an integer that determines the how many decimal digits the formatted number should have).

As in the second example, did you notice that the last two decimal digits (3 and 4) are not in the formatted number? That's because the minimum number of decimal digits we set in the options parameter as formatConfig, (minimumFractionDigits) was 2. See?

Apart from the format method on the formatterObject, there is also another method, the formatToParts method which returns an array of objects representing the number string in parts that can be used for custom locale-aware formatting.
For example:

const num = 1234.5678;

const britishNumberFormatter = new Intl.NumberFormat("en-GB");
const spanishNumberFormatter = new Intl.NumberFormat("es-ES");

  0: Object { type: "integer", value: "1" }
  1: Object { type: "group", value: "," }
  2: Object { type: "integer", value: "234" }
  3: Object { type: "decimal", value: "." }
  4: Object { type: "fraction", value: "568" }
console.log(spanishNumberFormatter.formatToParts(num)); // 1.234.567.890,123
  0: Object { type: "integer", value: "1234" }
  1: Object { type: "decimal", value: "," }
  2: Object { type: "fraction", value: "568" }
] */

formatToParts splits the formatted number into parts, and determines the digit type (integer or fraction) and the symbol type (group or decimal).

Other configuration options for options can be found in the MDN documentation for Intl.NumberFormat.

Experimental Features with Intl.NumberFormat

Some interesting features are being added to Intl.NumberFormat such as the ability to format with units (l, mi/h, mph), using exponential notations (E8, E-2) and BigInt support. These features cannot be used in production code yet. At the moment, only Chrome 77+ provides support for these features.

const num = 1235.12;
const formatConfig = {
  style: "units",
  unit: "meter-per-second",

// setup formatters
const britishNumberFormatter = new Intl.NumberFormat("en", formatConfig); // 1,235.12 m/s

It's a pity but at the time of this writing, Intl.NumberFormat does not exist in Node.js.

All the best of all the best as you use Intl.NumberFormat to display numbers in styles customised for human languages and human-readable formats.



Editor guide
tttony profile image

I needed to format a number and I just discovered that in spanish if the number 12345.67 it will print 12.345,67 cool but if the number is 1234.56 it will print 1234,56 not cool, it should be: 1.234,56, still looking a way to do it without regex

sudo_kaizen profile image
Orim Dominic Adah Author

Hello Tony. I am replying late, I guess, but I should. haha
What language locale are you converting from, and to?

tttony profile image

No problem, I read this: stackoverflow.com/questions/589913..., so it's an expected behaviour

jankapunkt profile image
Jan Küster

Thank you for pointing me to this. I read a lot of MDN documentation but yet I did not stumbled over this one. Powerful tool indeed.

sudo_kaizen profile image
Orim Dominic Adah Author

Whoa! Thanks! This feedback really means a lot! Blessings!