Back to Blog
JavaScriptIntlNumberFormatLocalization

JavaScript Intl.NumberFormat Guide

Master JavaScript Intl.NumberFormat for locale-aware number formatting including currencies and percentages.

B
Bootspring Team
Engineering
August 19, 2019
6 min read

The Intl.NumberFormat API provides locale-aware number formatting for currencies, percentages, and more. Here's how to use it.

Basic Usage#

1// Default formatting 2const formatter = new Intl.NumberFormat(); 3console.log(formatter.format(1234567.89)); // '1,234,567.89' (US English) 4 5// Specific locale 6const deFormatter = new Intl.NumberFormat('de-DE'); 7console.log(deFormatter.format(1234567.89)); // '1.234.567,89' 8 9const frFormatter = new Intl.NumberFormat('fr-FR'); 10console.log(frFormatter.format(1234567.89)); // '1 234 567,89' 11 12// Multiple locales (fallback) 13const formatter = new Intl.NumberFormat(['ban', 'id']); 14// Uses Indonesian if Balinese not available

Currency Formatting#

1// Basic currency 2const usdFormatter = new Intl.NumberFormat('en-US', { 3 style: 'currency', 4 currency: 'USD', 5}); 6console.log(usdFormatter.format(1234.56)); // '$1,234.56' 7 8// Different currencies 9const eurFormatter = new Intl.NumberFormat('de-DE', { 10 style: 'currency', 11 currency: 'EUR', 12}); 13console.log(eurFormatter.format(1234.56)); // '1.234,56 €' 14 15const jpyFormatter = new Intl.NumberFormat('ja-JP', { 16 style: 'currency', 17 currency: 'JPY', 18}); 19console.log(jpyFormatter.format(1234)); // '¥1,234' 20 21// Currency display options 22const options = { 23 style: 'currency', 24 currency: 'USD', 25 currencyDisplay: 'code', // 'symbol' | 'narrowSymbol' | 'code' | 'name' 26}; 27 28new Intl.NumberFormat('en-US', { ...options, currencyDisplay: 'symbol' }) 29 .format(1234); // '$1,234.00' 30new Intl.NumberFormat('en-US', { ...options, currencyDisplay: 'code' }) 31 .format(1234); // 'USD 1,234.00' 32new Intl.NumberFormat('en-US', { ...options, currencyDisplay: 'name' }) 33 .format(1234); // '1,234.00 US dollars'

Percentage Formatting#

1// Basic percentage 2const percentFormatter = new Intl.NumberFormat('en-US', { 3 style: 'percent', 4}); 5console.log(percentFormatter.format(0.25)); // '25%' 6 7// With decimals 8const precisePercent = new Intl.NumberFormat('en-US', { 9 style: 'percent', 10 minimumFractionDigits: 2, 11 maximumFractionDigits: 2, 12}); 13console.log(precisePercent.format(0.1234)); // '12.34%' 14 15// Different locales 16const dePercent = new Intl.NumberFormat('de-DE', { 17 style: 'percent', 18}); 19console.log(dePercent.format(0.25)); // '25 %'

Unit Formatting#

1// Basic unit 2const meterFormatter = new Intl.NumberFormat('en-US', { 3 style: 'unit', 4 unit: 'meter', 5}); 6console.log(meterFormatter.format(100)); // '100 m' 7 8// Compound units 9const speedFormatter = new Intl.NumberFormat('en-US', { 10 style: 'unit', 11 unit: 'kilometer-per-hour', 12}); 13console.log(speedFormatter.format(100)); // '100 km/h' 14 15// Unit display options 16const options = { 17 style: 'unit', 18 unit: 'liter', 19}; 20 21new Intl.NumberFormat('en-US', { ...options, unitDisplay: 'short' }) 22 .format(5); // '5 L' 23new Intl.NumberFormat('en-US', { ...options, unitDisplay: 'long' }) 24 .format(5); // '5 liters' 25new Intl.NumberFormat('en-US', { ...options, unitDisplay: 'narrow' }) 26 .format(5); // '5L' 27 28// Common units 29const units = [ 30 'byte', 'kilobyte', 'megabyte', 'gigabyte', 31 'celsius', 'fahrenheit', 32 'meter', 'kilometer', 'mile', 33 'gram', 'kilogram', 'pound', 34 'liter', 'gallon', 35 'second', 'minute', 'hour', 'day', 36];

Decimal Options#

1// Minimum/maximum integer digits 2const intFormatter = new Intl.NumberFormat('en-US', { 3 minimumIntegerDigits: 4, 4}); 5console.log(intFormatter.format(42)); // '0,042' 6 7// Minimum/maximum fraction digits 8const fractionFormatter = new Intl.NumberFormat('en-US', { 9 minimumFractionDigits: 2, 10 maximumFractionDigits: 4, 11}); 12console.log(fractionFormatter.format(1.5)); // '1.50' 13console.log(fractionFormatter.format(1.12345)); // '1.1235' 14 15// Significant digits 16const sigFormatter = new Intl.NumberFormat('en-US', { 17 minimumSignificantDigits: 3, 18 maximumSignificantDigits: 5, 19}); 20console.log(sigFormatter.format(1.2)); // '1.20' 21console.log(sigFormatter.format(12345.6)); // '12,346'

Notation Options#

1// Scientific notation 2const sciFormatter = new Intl.NumberFormat('en-US', { 3 notation: 'scientific', 4}); 5console.log(sciFormatter.format(1234567)); // '1.235E6' 6 7// Engineering notation 8const engFormatter = new Intl.NumberFormat('en-US', { 9 notation: 'engineering', 10}); 11console.log(engFormatter.format(1234567)); // '1.235E6' 12 13// Compact notation (K, M, B) 14const compactFormatter = new Intl.NumberFormat('en-US', { 15 notation: 'compact', 16}); 17console.log(compactFormatter.format(1234)); // '1.2K' 18console.log(compactFormatter.format(1234567)); // '1.2M' 19console.log(compactFormatter.format(1234567890)); // '1.2B' 20 21// Compact with display option 22const longCompact = new Intl.NumberFormat('en-US', { 23 notation: 'compact', 24 compactDisplay: 'long', 25}); 26console.log(longCompact.format(1234567)); // '1.2 million' 27 28// Compact in different locales 29const jaCompact = new Intl.NumberFormat('ja-JP', { 30 notation: 'compact', 31}); 32console.log(jaCompact.format(10000)); // '1万'

Sign Display#

1// Always show sign 2const alwaysSign = new Intl.NumberFormat('en-US', { 3 signDisplay: 'always', 4}); 5console.log(alwaysSign.format(42)); // '+42' 6console.log(alwaysSign.format(-42)); // '-42' 7console.log(alwaysSign.format(0)); // '+0' 8 9// Sign for non-zero only 10const exceptZero = new Intl.NumberFormat('en-US', { 11 signDisplay: 'exceptZero', 12}); 13console.log(exceptZero.format(42)); // '+42' 14console.log(exceptZero.format(-42)); // '-42' 15console.log(exceptZero.format(0)); // '0' 16 17// Accounting format for negative 18const accounting = new Intl.NumberFormat('en-US', { 19 style: 'currency', 20 currency: 'USD', 21 currencySign: 'accounting', 22}); 23console.log(accounting.format(-42)); // '($42.00)'

Format to Parts#

1// Get formatted parts as array 2const formatter = new Intl.NumberFormat('en-US', { 3 style: 'currency', 4 currency: 'USD', 5}); 6 7const parts = formatter.formatToParts(1234.56); 8console.log(parts); 9// [ 10// { type: 'currency', value: '$' }, 11// { type: 'integer', value: '1' }, 12// { type: 'group', value: ',' }, 13// { type: 'integer', value: '234' }, 14// { type: 'decimal', value: '.' }, 15// { type: 'fraction', value: '56' } 16// ] 17 18// Custom styling based on parts 19function formatWithStyles(number, formatter) { 20 return formatter.formatToParts(number).map(part => { 21 switch (part.type) { 22 case 'currency': 23 return `<span class="currency">${part.value}</span>`; 24 case 'integer': 25 return `<span class="integer">${part.value}</span>`; 26 case 'fraction': 27 return `<span class="fraction">${part.value}</span>`; 28 default: 29 return part.value; 30 } 31 }).join(''); 32}

Range Formatting#

1// Format number range 2const rangeFormatter = new Intl.NumberFormat('en-US', { 3 style: 'currency', 4 currency: 'USD', 5}); 6 7console.log(rangeFormatter.formatRange(100, 200)); 8// '$100.00 – $200.00' 9 10// Range with compact notation 11const compactRange = new Intl.NumberFormat('en-US', { 12 notation: 'compact', 13}); 14console.log(compactRange.formatRange(1000, 5000)); 15// '1K – 5K'

Rounding Options#

1// Rounding mode 2const ceilFormatter = new Intl.NumberFormat('en-US', { 3 maximumFractionDigits: 2, 4 roundingMode: 'ceil', 5}); 6console.log(ceilFormatter.format(1.234)); // '1.24' 7 8const floorFormatter = new Intl.NumberFormat('en-US', { 9 maximumFractionDigits: 2, 10 roundingMode: 'floor', 11}); 12console.log(floorFormatter.format(1.236)); // '1.23' 13 14// Rounding increment 15const nickelFormatter = new Intl.NumberFormat('en-US', { 16 style: 'currency', 17 currency: 'USD', 18 roundingIncrement: 5, 19 maximumFractionDigits: 2, 20}); 21console.log(nickelFormatter.format(1.22)); // '$1.20' 22console.log(nickelFormatter.format(1.23)); // '$1.25'

Practical Examples#

1// Price formatter 2function formatPrice(amount, currency = 'USD', locale = 'en-US') { 3 return new Intl.NumberFormat(locale, { 4 style: 'currency', 5 currency, 6 }).format(amount); 7} 8 9// File size formatter 10function formatFileSize(bytes) { 11 const units = ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte']; 12 let unitIndex = 0; 13 let size = bytes; 14 15 while (size >= 1024 && unitIndex < units.length - 1) { 16 size /= 1024; 17 unitIndex++; 18 } 19 20 return new Intl.NumberFormat('en-US', { 21 style: 'unit', 22 unit: units[unitIndex], 23 maximumFractionDigits: 2, 24 }).format(size); 25} 26 27console.log(formatFileSize(1234567890)); // '1.15 GB' 28 29// Compact number with threshold 30function formatNumber(num, compact = true) { 31 const options = compact && Math.abs(num) >= 1000 32 ? { notation: 'compact', maximumFractionDigits: 1 } 33 : { maximumFractionDigits: 0 }; 34 35 return new Intl.NumberFormat('en-US', options).format(num); 36}

Caching Formatters#

1// Cache formatters for performance 2const formatters = new Map(); 3 4function getCurrencyFormatter(currency, locale = 'en-US') { 5 const key = `${locale}-${currency}`; 6 7 if (!formatters.has(key)) { 8 formatters.set( 9 key, 10 new Intl.NumberFormat(locale, { 11 style: 'currency', 12 currency, 13 }) 14 ); 15 } 16 17 return formatters.get(key); 18} 19 20// Usage 21const usd = getCurrencyFormatter('USD'); 22console.log(usd.format(100)); // '$100.00'

Best Practices#

Locale Handling: ✓ Use user's locale when possible ✓ Provide locale fallbacks ✓ Test with multiple locales ✓ Consider right-to-left locales Currency: ✓ Use ISO 4217 currency codes ✓ Match locale to currency region ✓ Consider currencyDisplay option ✓ Handle accounting format Performance: ✓ Cache formatter instances ✓ Reuse formatters ✓ Avoid creating in loops ✓ Use formatToParts for custom display Avoid: ✗ Manual number formatting ✗ String concatenation for currency ✗ Ignoring locale differences ✗ Creating formatters repeatedly

Conclusion#

Intl.NumberFormat provides comprehensive locale-aware number formatting for currencies, percentages, units, and general numbers. Use it instead of manual string manipulation to ensure correct formatting across different locales. Cache formatter instances for performance and use formatToParts when you need fine-grained control over the output display.

Share this article

Help spread the word about Bootspring