Format Currencies and "1.2K" Counts Without a Library
Money formatting is where hand-rolled code goes to embarrass itself: '$' + price.toFixed(2) works right up until you need euros, or thousands separators, or a locale where the symbol goes after the number. The browser has a complete solution built in.
Currency
const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
usd.format(1234.5); // "$1,234.50"
const eur = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
eur.format(1234.5); // "1.234,50 €"
Separators, symbol placement, decimal conventions - all handled per locale. Pass navigator.language as the locale and prices render the way each visitor expects, while the currency itself stays whatever your store charges in.
Compact notation: the "12.5K views" formatter
const compact = new Intl.NumberFormat('en', {
notation: 'compact',
maximumFractionDigits: 1,
});
compact.format(12500); // "12.5K"
compact.format(3400000); // "3.4M"
Every social-style counter you've ever seen, one option. Localized too - German gives "12.500" vs "12,5 Tsd." depending on settings.
Percent and units
new Intl.NumberFormat('en', { style: 'percent', maximumFractionDigits: 1 })
.format(0.847); // "84.7%" (note: input is the fraction!)
new Intl.NumberFormat('en', { style: 'unit', unit: 'megabyte' })
.format(245); // "245 MB"
new Intl.NumberFormat('en', { style: 'unit', unit: 'kilometer-per-hour' })
.format(88); // "88 km/h"
The percent style multiplying by 100 for you is the classic first-use surprise: format(84.7) prints "8,470%".
Performance note that actually matters
Formatter construction is heavyweight; format() calls are cheap. In a list of 500 prices, create one formatter outside the loop. I keep a memoized helper around:
const formatters = {};
function money(amount, currency = 'USD', locale = navigator.language) {
const key = locale + currency;
formatters[key] ??= new Intl.NumberFormat(locale, { style: 'currency', currency });
return formatters[key].format(amount);
}
Same rule as Intl.RelativeTimeFormat for timestamps: build once, format often.
Support is universal, including Node. Between this, RelativeTimeFormat and Intl.ListFormat ("a, b, and c"), the days of shipping a formatting library to the client are over for most apps.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.