Intl.NumberFormat
JavaScript has a number formatter (part of the Internationalization API).
// Create our number formatter.
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
// These options can be used to round to whole numbers.
trailingZeroDisplay: 'stripIfInteger' // This is probably what most people
// want. It will only stop printing
// the fraction when the input
// amount is a round number (int)
// already. If that's not what you
// need, have a look at the options
// below.
//minimumFractionDigits: 0, // This suffices for whole numbers, but will
// print 2500.10 as $2,500.1
//maximumFractionDigits: 0, // Causes 2500.99 to be printed as $2,501
});
// Use the formatter with the value of an input.
let input = document.getElementById('amount');
input.addEventListener('keyup', e => {
document.getElementById('result').innerText = formatter.format(e.target.value);
});
input.dispatchEvent(new Event('keyup'));
<label>
Amount
<input id="amount" value="2500">
</label>
Result:
<span id="result"></span>
Use undefined in place of the first argument ('en-US' in the example) to use the system locale (the user locale in case the code is running in a browser). Further explanation of the locale code.
Here's a list of the currency codes.
Intl.NumberFormat vs Number.prototype.toLocaleString
A final note comparing this to the older .toLocaleString. They both offer essentially the same functionality. However, toLocaleString in its older incarnations (pre-Intl) does not actually support locales: it uses the system locale. So when debugging old browsers, be sure that you're using the correct version (MDN suggests to check for the existence of Intl). There isn't any need to worry about this at all if you don't care about old browsers or just use the shim.
Also, the performance of both is the same for a single item, but if you have a lot of numbers to format, using Intl.NumberFormat is ~70 times faster. Therefore, it's usually best to use Intl.NumberFormat and instantiate only once per page load. Anyway, here's the equivalent usage of toLocaleString:
console.log((2500).toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
})); /* $2,500.00 */
Some notes on browser support and Node.js
- Browser support is no longer an issue nowadays with 99+% support globally
- There is a shim to support it on fossilized browsers (like Internet Explorer 8), should you really need to
- Node.js before v13 only supports
en-USout of the box. One solution is to install full-icu, see here for more information - Have a look at CanIUse for more information
How to handle prices/currency formatting in Javascript?
Format numbers as currency | Adobe Acrobat
How to format numbers into currency format on MAKE
How to Format number as currency in JavaScript?
Videos
Intl.NumberFormat
JavaScript has a number formatter (part of the Internationalization API).
// Create our number formatter.
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
// These options can be used to round to whole numbers.
trailingZeroDisplay: 'stripIfInteger' // This is probably what most people
// want. It will only stop printing
// the fraction when the input
// amount is a round number (int)
// already. If that's not what you
// need, have a look at the options
// below.
//minimumFractionDigits: 0, // This suffices for whole numbers, but will
// print 2500.10 as $2,500.1
//maximumFractionDigits: 0, // Causes 2500.99 to be printed as $2,501
});
// Use the formatter with the value of an input.
let input = document.getElementById('amount');
input.addEventListener('keyup', e => {
document.getElementById('result').innerText = formatter.format(e.target.value);
});
input.dispatchEvent(new Event('keyup'));
<label>
Amount
<input id="amount" value="2500">
</label>
Result:
<span id="result"></span>
Use undefined in place of the first argument ('en-US' in the example) to use the system locale (the user locale in case the code is running in a browser). Further explanation of the locale code.
Here's a list of the currency codes.
Intl.NumberFormat vs Number.prototype.toLocaleString
A final note comparing this to the older .toLocaleString. They both offer essentially the same functionality. However, toLocaleString in its older incarnations (pre-Intl) does not actually support locales: it uses the system locale. So when debugging old browsers, be sure that you're using the correct version (MDN suggests to check for the existence of Intl). There isn't any need to worry about this at all if you don't care about old browsers or just use the shim.
Also, the performance of both is the same for a single item, but if you have a lot of numbers to format, using Intl.NumberFormat is ~70 times faster. Therefore, it's usually best to use Intl.NumberFormat and instantiate only once per page load. Anyway, here's the equivalent usage of toLocaleString:
console.log((2500).toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
})); /* $2,500.00 */
Some notes on browser support and Node.js
- Browser support is no longer an issue nowadays with 99+% support globally
- There is a shim to support it on fossilized browsers (like Internet Explorer 8), should you really need to
- Node.js before v13 only supports
en-USout of the box. One solution is to install full-icu, see here for more information - Have a look at CanIUse for more information
Number.prototype.toFixed
This solution is compatible with every single major browser:
const profits = 2489.8237;
profits.toFixed(3) // Returns 2489.824 (rounds up)
profits.toFixed(2) // Returns 2489.82
profits.toFixed(7) // Returns 2489.8237000 (pads the decimals)
All you need is to add the currency symbol (e.g. "$" + profits.toFixed(2)) and you will have your amount in dollars.
Custom function
If you require the use of , between each digit, you can use this function:
function formatMoney(number, decPlaces, decSep, thouSep) {
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces,
decSep = typeof decSep === "undefined" ? "." : decSep;
thouSep = typeof thouSep === "undefined" ? "," : thouSep;
var sign = number < 0 ? "-" : "";
var i = String(parseInt(number = Math.abs(Number(number) || 0).toFixed(decPlaces)));
var j = (j = i.length) > 3 ? j % 3 : 0;
return sign +
(j ? i.substr(0, j) + thouSep : "") +
i.substr(j).replace(/(\decSep{3})(?=\decSep)/g, "$1" + thouSep) +
(decPlaces ? decSep + Math.abs(number - i).toFixed(decPlaces).slice(2) : "");
}
document.getElementById("b").addEventListener("click", event => {
document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>
Use it like so:
(123456789.12345).formatMoney(2, ".", ",");
If you're always going to use '.' and ',', you can leave them off your method call, and the method will default them for you.
(123456789.12345).formatMoney(2);
If your culture has the two symbols flipped (i.e., Europeans) and you would like to use the defaults, just paste over the following two lines in the formatMoney method:
d = d == undefined ? "," : d,
t = t == undefined ? "." : t,
Custom function (ES6)
If you can use modern ECMAScript syntax (i.e., through Babel), you can use this simpler function instead:
function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = ",") {
try {
decimalCount = Math.abs(decimalCount);
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
const negativeSign = amount < 0 ? "-" : "";
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
let j = (i.length > 3) ? i.length % 3 : 0;
return negativeSign +
(j ? i.substr(0, j) + thousands : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) +
(decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
} catch (e) {
console.log(e)
}
};
document.getElementById("b").addEventListener("click", event => {
document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>
When I try to add the total of the items (being fetched from an API), I am currently returning a string. When I try to convert it to a number, the formatting is off for USD.
For example, how can I convert a string of a number such as "131.40" to the number 131.40, or "14.1" to the number 14.10?
I understand that the biggest issue has to do with the numbers being floating point math. But I'm unclear on how to handle this problem. Do I convert the way my prices are being currently displayed? Any advice appreciated.
Here is the full context of my code:
const products = [{
id: 1,
price: 109.1,
quantity: 1,
title: "T-Shirt"
},
{
id: 2,
price: 22.3,
quantity: 1,
title: "Jeans"
}]
function totalPrice(storageItems){
const totalPriceHolder = []
storageItems.map((a, index) => {
const totalPrice = a.price * a.quantity;
totalPriceHolder.push((totalPrice))
})
console.log("Check1", totalPriceHolder)
const totalPriceReduce = totalPriceHolder.reduce((a, b) => a + b, 0).toFixed(2);
console.log("Check 2", totalPriceReduce)
return parseFloat(totalPriceReduce)
}
console.log(totalPrice(products))