Rxova
Skip to content

Currency input — Migrating

Two props swapped names in 0.2.0, so that this input emits its value through onChange like every other input in the suite:

0.1.x0.2.0
onValueChange(value, meta)onChange(value, meta)
onChange(event) (DOM)onNativeChange(event)
Terminal window
npx @rxova/codemod currency-on-change ./src

Do run the codemod rather than a find-and-replace. The two renames have to happen in one pass: doing onValueChangeonChange first and onChangeonNativeChange second walks the value handler through both steps and silently lands it on the native prop.

onValueChange remains as a deprecated compatibility alias and still fires — with a development warning — so a codebase can migrate one call site at a time.

Why: every other input in the suite emits a plain value from onChange, and this package’s own README has said so since before this component existed. It was the only one where onChange meant the DOM event and the value arrived under a different name, which is the sort of inconsistency that costs a reader more than it ever cost us to keep.

The two libraries solve the same problem differently. react-currency-input-field derives a separator from one probe and then applies that separator while rebuilding the editable value; this package delegates each complete idle value to Intl and uses formatToParts() only to parse the user’s locale-specific input.

react-currency-input-field@rxova/react-intl-currency-input
intlConfig={{ locale, currency }}locale + currency (top-level props)
groupSeparator / decimalSeparator(derived from the locale — remove them)
prefix / suffix(derived from the currency — remove them)
decimalScalemaximumFractionDigits
fixedDecimalLengthminimumFractionDigits + maximumFractionDigits
allowNegativeValueallowNegative
stepstep
transformRawValuetransformRawValue
value (string)value (number | null)
onValueChange(value, name, values)onChange(value, meta)value is a number | null
import { useState } from 'react'
import CurrencyInput from 'react-currency-input-field'
function BeforeMigration() {
const [value, setValue] = useState<string | undefined>()
return (
<CurrencyInput
intlConfig={{ locale: 'bg-BG', currency: 'EUR' }}
groupSeparator=" "
decimalSeparator=","
decimalScale={2}
value={value}
onValueChange={setValue}
/>
)
}
import { useState } from 'react'
import { CurrencyInput } from '@rxova/react-intl-currency-input'
function AfterMigration() {
const [value, setValue] = useState<number | null>(null)
return <CurrencyInput locale="bg-BG" currency="EUR" value={value} onChange={setValue} />
}
  • Bulgarian grouping is correct. A hardcoded groupSeparator=" " uses an ASCII space and groups below 10000. Version 4.0.6’s locale probe uses 1000.1; Bulgarian intentionally emits no group part for that value, so the derived separator is empty. Here the non-breaking separator and the “only above 9999” threshold come from Intl/CLDR automatically.
  • The value is a number. No more parsing a formatted string back into a number before you submit.
  • Fewer props. Separators, prefix/suffix, and fraction digits default from the locale and currency.
  • Live formatting with a stable caret. Like react-currency-input-field, this formats as you type; the caret is anchored to the digit you typed rather than the character index, so grouping changes never move it. Prefer no caret logic at all? formatMode="blur" edits a plain number while focused and formats on blur.
  • Native digits round-trip. Arabic and other numbering systems are mapped through Intl rather than an ASCII-only parser.
  • Your change handler is now onChange and receives a number | null, not a string. Update anything that did string work on it.
  • If you relied on a custom separator that did not match the locale, switch to the correct locale instead.
  • Abbreviations such as 1k, arbitrary prefixes/suffixes, and customInput are intentionally not supported. They make the field a generic numeric mask rather than a locale-defined currency input. Use transformRawValue for application-specific cleanup before parsing.