Numbers and Currencies
 The  @internationalized/number  package provides tools for formatting numbers,
currencies, and units in a locale-aware way. It builds on the native  Intl.NumberFormat  API while adding additional features and fixing inconsistencies across browsers. 
Installation
 npm install @internationalized/number 
npm
 
yarn
 
pnpm
 
bun
 NumberFormatter
 The  NumberFormatter  class is the primary way to format numbers, currencies, and units. 
Basic Number Formatting
 import { NumberFormatter } from "@internationalized/number";
 
const formatter = new NumberFormatter("en-US", {
  style: "decimal", // "decimal" | "percent" | "currency" | "unit"
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});
 
console.log(formatter.format(1234.567)); // "1,234.57" Currency Formatting
 const currencyFormatter = new NumberFormatter("en-US", {
  style: "currency",
  currency: "USD",
});
 
console.log(currencyFormatter.format(1234.56)); // "$1,234.56" Percentage Formatting
 const percentFormatter = new NumberFormatter("en-US", {
  style: "percent",
  maximumFractionDigits: 1,
});
 
console.log(percentFormatter.format(0.456)); // "45.6%" Unit Formatting
 const unitFormatter = new NumberFormatter("en-US", {
  style: "unit",
  unit: "kilometer-per-hour",
});
 
console.log(unitFormatter.format(60)); // "60 km/h" NumberParser
The NumberParser class helps parse user input into numbers while respecting locale-specific formatting (e.g., decimal separators).
 import { NumberParser } from "@internationalized/number";
 
const parser = new NumberParser("en-US");
console.log(parser.parse("1,234.56")); // 1234.56
 
const germanParser = new NumberParser("de-DE");
console.log(germanParser.parse("1.234,56")); // 1234.56 (in German, comma is the decimal separator) Number Utilities
NumberFormatOptions
The package provides TypeScript types for number formatting options:
 import type { NumberFormatOptions } from "@internationalized/number";
 
const options: NumberFormatOptions = {
  style: "currency",
  currency: "EUR",
  currencyDisplay: "symbol", // "symbol" | "narrowSymbol" | "code" | "name"
}; Currency & Unit Types
Predefined types for supported currencies and units:
 import type { Currency, Unit } from "@internationalized/number";
 
const currency: Currency = "JPY"; // Autocomplete for supported currencies
const unit: Unit = "kilogram";    // Autocomplete for supported units Common Use Cases
Formatting User Input
 const formatter = new NumberFormatter("en-US", { style: "decimal" });
const parser = new NumberParser("en-US");
 
function formatInput(value: string) {
  const number = parser.parse(value);
  return isNaN(number) ? "" : formatter.format(number);
}
 
console.log(formatInput("1234.567")); // "1,234.567" Dynamic Currency Display
 function formatCurrency(value: number, currency: string, locale: string) {
  const formatter = new NumberFormatter(locale, {
    style: "currency",
    currency,
  });
  return formatter.format(value);
}
 
console.log(formatCurrency(99.99, "EUR", "fr-FR")); // "99,99 €"
console.log(formatCurrency(99.99, "JPY", "ja-JP")); // "¥100" (Yen has no decimals) Localized Unit Conversion
 function formatSpeed(speedKmh: number, locale: string) {
  const formatter = new NumberFormatter(locale, {
    style: "unit",
    unit: "kilometer-per-hour",
  });
  return formatter.format(speedKmh);
}
 
console.log(formatSpeed(60, "en-US")); // "60 km/h"
console.log(formatSpeed(60, "de-DE")); // "60 km/h" (but formatted with German conventions) Common Gotchas
- Locale-Specific Formatting:
- Decimal and grouping separators vary by locale (1,234.56 vs 1.234,56).
- Always use NumberParser when reading user input.
- Currency Rounding:
- Some currencies (like JPY) don’t use decimals.
- Performance:
- Reuse NumberFormatter instances instead of creating new ones in render loops.
- Unit Variations:
- Some units may display differently in certain locales (e.g., “L” vs “ℓ” for liters).
- Fallback Locales:
- If a locale isn’t supported, the browser may fall back to a default.
Advanced Usage
Custom Formatting with NumberFormatOptions
 const customFormatter = new NumberFormatter("en-US", {
  style: "currency",
  currency: "USD",
  currencyDisplay: "narrowSymbol", // "$" instead of "US$"
  notation: "compact", // "compact" | "scientific" | "engineering"
  compactDisplay: "short", // "short" | "long"
});
 
console.log(customFormatter.format(1_000_000)); // "$1M" Sign Display Options
 const accountingFormatter = new NumberFormatter("en-US", {
  style: "currency",
  currency: "USD",
  signDisplay: "exceptZero", // "auto" | "never" | "always" | "exceptZero"
});
 
console.log(accountingFormatter.format(100)); // "+$100.00"
console.log(accountingFormatter.format(0));   // "$0.00" Range Formatting
 const rangeFormatter = new NumberFormatter("en-US", {
  style: "currency",
  currency: "EUR",
});
 
console.log(rangeFormatter.formatRange(100, 200)); // "€100.00 – €200.00"