Ship internal tools in hours, not weeks. Real auth, users, jobs, audit logs, and cohesive UI included. Early access $249 $499 → [Get it now]

How to format a number as currency in JavaScript

Formatting numbers as currency is essential for e-commerce applications, financial dashboards, pricing components, and shopping cart interfaces in JavaScript. With over 25 years of experience in software development and as the creator of CoreUI, I’ve implemented currency formatting in price displays, checkout forms, and financial tables across our Angular and React component libraries. The modern standard is Intl.NumberFormat — it handles locale-specific symbols, decimal separators, and digit grouping automatically without any manual string manipulation.

Use Intl.NumberFormat with style: 'currency' to format a number as currency.

new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(1234.56)
// '$1,234.56'

1. Basic Currency Formatting

Pass a BCP 47 locale tag and an ISO 4217 currency code. The formatter handles symbol placement, digit grouping, and decimal precision for that locale automatically.

const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
usd.format(1234.56)    // '$1,234.56'
usd.format(0.5)        // '$0.50'
usd.format(-99.9)      // '-$99.90'

const eur = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' })
eur.format(1234.56)    // '1.234,56 €'  — symbol after, comma as decimal

const gbp = new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' })
gbp.format(1234.56)    // '£1,234.56'

const jpy = new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' })
jpy.format(1234.56)    // '¥1,235'  — JPY has no subunit, rounds to integer

The same number formats differently per locale — symbol position, decimal separator, and thousands separator all change automatically.

2. Reusable Formatter (Cache for Performance)

Creating a new Intl.NumberFormat instance is relatively expensive. Cache the formatter when formatting many values.

const currencyFormatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
})

const prices = [9.99, 24.50, 149.00, 1299.99]
const formatted = prices.map(p => currencyFormatter.format(p))
// ['$9.99', '$24.50', '$149.00', '$1,299.99']

3. Controlling Display Options

Intl.NumberFormat exposes options to control how the currency appears.

// Symbol (default) — '$1,234.56'
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD',
  currencyDisplay: 'symbol' }).format(1234.56)

// ISO code — 'USD 1,234.56'
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD',
  currencyDisplay: 'code' }).format(1234.56)

// Full name — '1,234.56 US dollars'
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD',
  currencyDisplay: 'name' }).format(1234.56)

// Narrow symbol (no disambiguation) — '$1,234.56'
new Intl.NumberFormat('en-CA', { style: 'currency', currency: 'USD',
  currencyDisplay: 'narrowSymbol' }).format(1234.56)

4. Accounting Format for Negative Values

Financial UIs often display negative values in parentheses rather than with a minus sign. Use currencySign: 'accounting'.

const accounting = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
  currencySign: 'accounting'
})

accounting.format(1234.56)   // '$1,234.56'
accounting.format(-1234.56)  // '($1,234.56)'  — parentheses, not minus

5. Why Not toFixed(2)?

toFixed(2) is tempting but fails for international use: it produces a plain string with no symbol, uses the wrong decimal separator for non-English locales, and gets the symbol placement wrong in many currencies.

// Manual approach — fragile
'$' + (1234.56).toFixed(2)    // '$1234.56'  — missing thousands separator
'€' + (1234.56).toFixed(2)    // '€1234.56'  — symbol on wrong side for German locale
'¥' + (1234.56).toFixed(2)    // '¥1234.56'  — JPY doesn't use decimals

// Intl.NumberFormat — correct for every locale
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(1234.56)
// '1.234,56 €'

Avoid toFixed() for currency display in any application that may reach international users. See how to round a number in JavaScript if you need to round before formatting.

6. Formatting a Table of Prices

A common pattern in dashboards is formatting a whole dataset for display.

const products = [
  { name: 'Widget', price: 9.99 },
  { name: 'Gadget', price: 49.50 },
  { name: 'Doohickey', price: 149.00 }
]

const fmt = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })

products.map(p => ({ ...p, displayPrice: fmt.format(p.price) }))
// [
//   { name: 'Widget',    price: 9.99,   displayPrice: '$9.99'   },
//   { name: 'Gadget',    price: 49.5,   displayPrice: '$49.50'  },
//   { name: 'Doohickey', price: 149,    displayPrice: '$149.00' }
// ]

Keep the raw price number for calculations and add displayPrice as a separate display-only string — never use formatted strings in arithmetic.

Best Practice Note:

Always use Intl.NumberFormat for currency display — it is the only approach that handles symbol placement, decimal and thousands separators, and rounding correctly across all locales. Cache formatter instances when processing arrays of values. Store monetary values as plain numbers (or integers in the smallest currency unit, e.g. cents) and only format at the display layer.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author