React-number-format: How to use currency format to fill decimal/cents first?

Created on 21 Oct 2019  路  12Comments  路  Source: s-yadav/react-number-format

Consider the following input value:
12345

The output would be:
$ 123.45 instead of $ 1,2345.00.

How to achieve the first output using this library?

This is how I am using right now, unfortunately I couldn't make it work as desired:

<NumberFormat
  customInput={Input}
  decimalScale={2}
  decimalSeparator=","
  fixedDecimalScale
  onKeyDown={onEnter(handleEnter)}
  onValueChange={handleValueChange}
  placeholder="$ 0,00"
  prefix="$ "
  thousandSeparator="."
  value={value}
/>

Most helpful comment

@felri I've found out how to format the number properly - using a formatter. The trick is to divide value by 100.

export default function currencyFormatter(value) {
  if (!Number(value)) return "";

  const amount = new Intl.NumberFormat("pt-BR", {
    style: "currency",
    currency: "BRL"
  }).format(value / 100);

  return `${amount}`;
}

Then you must use this format into your component:

<NumberFormat {...allOtherRequiredProps} format={currencyFormatter} />

All 12 comments

I would like to know this as well

Both outputs you mentioned seems incorrect. It should be $ 12.345.00 as you have mentioned fixedDecimalScale. Also, don't forget to pass the isNumericString prop. If you are passing a numeric string as value.

@s-yadav It depends on which locale you are referring. It is correct when using, for instance, pt-BR.

@felri I've found out how to format the number properly - using a formatter. The trick is to divide value by 100.

export default function currencyFormatter(value) {
  if (!Number(value)) return "";

  const amount = new Intl.NumberFormat("pt-BR", {
    style: "currency",
    currency: "BRL"
  }).format(value / 100);

  return `${amount}`;
}

Then you must use this format into your component:

<NumberFormat {...allOtherRequiredProps} format={currencyFormatter} />

@richardaum That's the trick. Thank you very much!

@richardaum thank you, works great

@richardaum I tried with this approach, but the values object returns float value wrongly.

For example, if I type 12345, the field shows R$ 123,45, but the values object returns {formattedValue: "R$聽123,45", value: "12345", floatValue: 12345}

Did this happen to you?

Yeah. This is expected because the approach is based on a formatter only.
So it will only change how the number is displayed. You must handle the
float number and divide it by 100 before persisting it or whatever you do
with this number.

An alternative could be if a implementation is made to make this feature
native, then we could expect float number also be divide by 100
automatically.

You could also implement your own wrapper to this component and expose a
float number already divided by 100.

@felri I've found out how to format the number properly - using a formatter. The trick is to divide value by 100.

export default function currencyFormatter(value) {
  if (!Number(value)) return "";

  const amount = new Intl.NumberFormat("pt-BR", {
    style: "currency",
    currency: "BRL"
  }).format(value / 100);

  return `${amount}`;
}

Then you must use this format into your component:

<NumberFormat {...allOtherRequiredProps} format={currencyFormatter} />

Please number formatter ?

@richardaum Thank you so much! (Valeu demais velho)

To clarify, format only transforms the value in the UI.

To make sure I get the right value in onValueChange I used:

onValueChange={values => {
    if(!onValueChange) { return; }
    const val = (parseFloat(values.value) / 100).toFixed(2)
    const floatVal = values.floatValue && values.floatValue / 100
    onValueChange({value: val, floatValue: floatVal, formattedValue, values.formattedValue})
}}

So if I type 900, val === "9.00" and floatVal === 9, while values.value === "900" and values.floatValue === 900.

I also had to fix the initial value

value={String(parseFloat(value + "" ?? "0") * 100)}

+ "" is to coerce number to string, ?? "0" is to default to "0" if value is undefined.

With these changes, internally the value is still 900 but on the consumer side the value is 9.00

Additionally, I had to fix the caret positioning with

onFocus={e => {
  if (inputRef.current && value) {
    const positionLastDigit = inputRef.current.value.length - suffix.length;
    setCaretPosition(inputRef.current, positionLastDigit);
  }
  props.onFocus && props.onFocus(e);
}}

with setCaretPosition being a rip-off of https://github.com/s-yadav/react-number-format/blob/8af37958c69ff1e0252282d37e922a913e52e046/lib/utils.js#L146

Yeah. This is expected because the approach is based on a formatter only. So it will only change how the number is displayed. You must handle the float number and divide it by 100 before persisting it or whatever you do with this number. An alternative could be if a implementation is made to make this feature native, then we could expect float number also be divide by 100 automatically. You could also implement your own wrapper to this component and expose a float number already divided by 100.

Thats works perfectly for me, also the other solution. Many thanks.

Also you need to fix setting the value externally and returning the right value as said here:

To clarify, format only transforms the value in the UI.

To make sure I get the right value in onValueChange I used:

onValueChange={values => {
  if(!onValueChange) { return; }
  const val = (parseFloat(values.value) / 100).toFixed(2)
  const floatVal = values.floatValue && values.floatValue / 100
  onValueChange({value: val, floatValue: floatVal, formattedValue, values.formattedValue})
}}

So if I type 900, val === "9.00" and floatVal === 9, while values.value === "900" and values.floatValue === 900.

I also had to fix the initial value

value={String(parseFloat(value + "" ?? "0") * 100)}

+ "" is to coerce number to string, ?? "0" is to default to "0" if value is undefined.

With these changes, internally the value is still 900 but on the consumer side the value is 9.00

Additionally, I had to fix the caret positioning with

onFocus={e => {
  if (inputRef.current && value) {
    const positionLastDigit = inputRef.current.value.length - suffix.length;
    setCaretPosition(inputRef.current, positionLastDigit);
  }
  props.onFocus && props.onFocus(e);
}}

with setCaretPosition being a rip-off of

https://github.com/s-yadav/react-number-format/blob/8af37958c69ff1e0252282d37e922a913e52e046/lib/utils.js#L146

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arpontes picture arpontes  路  7Comments

cescoferraro picture cescoferraro  路  6Comments

leonardojobim picture leonardojobim  路  3Comments

lucasglobalsys picture lucasglobalsys  路  5Comments

maitedev picture maitedev  路  7Comments