The Best Way to Format Percentages in JavaScript

Picture of me, Omari
Omari Thompson-Edwards
Mon Jan 29 2024 3 min

Formatting percentages is a common problem you'll run into in your JavaScript apps, whether it's for formatting numbers nicely for users, or improving your debugging logs. In this article we'll talk through two approaches - the manual way, and the relatively new built-in methods for handling percentages in JavaScript.

Manually.

At their core, percentages are just decimals multiplied by 100. This means we can pretty easily create a function:

function formatPercentage(n: number) {
    return `${n * 100}%`;
}

Or if you need a fixed number of decimal places, then we can use the "toFixed" method attached to numbers:

function formatPercentage(n: number) {
    return `${(n*100).toFixed(2)}%`;
}

Both these functions assume you're inputting your number as a decimal - if your number is already out of 100, then you can feel free to get rid of the multiplication:

function formatPercentage(n: number) {
    return `${n.toFixed(2)}%`;
}

Intl.NumberFormat.

Thanks to ES6, instead of doing it manually there is another option - the JavaScript built-in object "Intl.NumberFormat". You can use it to format numbers in all kinds of ways, from different currencies, for different locales, and usefully for us, into percentages.

Here's what it looks like:

const percentage = new Intl.NumberFormat('default', {
    style: 'percent',
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
}).format(0.5);
console.log(percentage);

And here's what gets printed:

Code_FLTv2WCa1J.png

Hopefully pretty straightforward - we can use the "Intl.NumberFormat" constructor to create a new number formatted object. It takes a locale as a parameter. This is more obvious for formatting different currencies, but even percentage formatting can vary between locales. Many countries in Europe for example swap the decimal point for a comma. The default locale depends on the system the code is running on - in my case "en-GB". If we change that to "fr-FR" for example, the percentage is printed slightly differently:

Code_NAlTWGZDFN.png

Hopefully not an issue for whatever your use case is, but something to be aware of if for example, you're expecting the output to always be 5 characters, or expecting to be able to split the whole and decimal parts by a ".".

The next parameter is an options object. There are a lot of options, but the main ones that are relevant for formatting percentages are:

  • minimumIntegerDigits
    • Defaults to 1, must be 1 to 21
    • Left-pads the number with zeroes to meet the minimum length
  • minimumFractionDigits
    • Defaults to 0
    • Right-pads the fraction digits to meet the minimum length
  • maximumFractionDigits
    • Defaults to 3, or minimumFractionDigits, whichever is greater
  • minimumSignificantDigits
    • Defaults to 1, must be 1 to 21
  • maximumSignificantDigits
    • Defaults to 21, must be 1 to 21
  • roundingPriority
    • "auto", "morePrecision" or "lessPrecision"
    • Handles conflicts between minimum/maximum integer/fraction digits, and the significant digits options

There is no maximumIntegerDigits, which makes sense when you think about it - if we did have a max and we went over it, constraining it to a maximum would mean changing the value.

Again one important thing to note is that the formatter handles formatting decimal values. That means that for a percentage of 37%, you'd want to input 0.37, not 37.

For a full in-depth explanation of all the options, you can check the MDN docs.

Conclusion.

So there's two options - if you're not sure which one to go with, I would just use "Intl.NumberFormatter".It is more verbose, but with that verbosity comes with reliability and flexibility. It allows you to handle different locales easily, and it offers a lot of control on how you format the percentage, so if you need an advanced use-case it can probably handle it before you reach to manually formatting your percentage.

Thanks for reading! If you liked this article, feel free to share it.

read more.

Me
Hey, I'm Omari 👋

I'm a full-stack developer from the UK. I'm currently looking for graduate and freelance software engineering roles, so if you liked this article, feel free to reach out.