Format currency input field with commas in typescript

Viewed 41
const valueRef = React.useRef<HTMLInputElement>(null);
const CurrencyInput = () => {
    const [focus, setFocus] = React.useState<boolean>(false);
    return (
      <>
          <CurrencyContainer
            onClick={() => valueRef.current?.focus()}
            isFocused={focus}
          >
            <CurrencyInput
              type="number"
              value={storage.updatesomevalue}
              onChange={e => dispatch(updatesomevalue(parseInt(e.target.value)))}
              ref={valueRef}
              onFocus={() => setFocus(true)}
              onBlur={() => setFocus(false)}
            />
            <Currency>USD</Currency>
          </CurrencyContainer>
      </>
    );
  };

<CurrencyContainer> is a styled div, CurrencyInput is a styled input, and <Currency> is a styled p.

I found the perfect behavior I'm looking for within this question here (I don't need the dollar sign) but haven't been able to integrate it within my existing code. Format currency input field with dollar sign & commas

Could someone please help me implement this within my typescript react function?

Edit: A lot of people have asked what I'm trying to do ... I'm trying to make sure the numbers into the currency input are comma separated for visibility. I want 1000000 to be visible as 1,000,000.

1 Answers

It was nice that you added some of your code. It might be helpful to you and others if you include some attempt at what you are trying to do.

I haven't tested it very much, but the idea here is that the input is now a "text" input with a pattern filter. Any keypress is dispatched to the useReducer function -- which takes the string representation of the user's input and breaks it into the whole and fractional values (if there's a decimal point) - then we strip commas, and ensure that the decimal value isn't more than two numbers.

I modified your components to just a div and input - so you'll need to fix that up.

import "./styles.css";
import React from "react";

const CurrencyInput = () => {
  const valueRef = React.useRef<HTMLInputElement>(null);
  const [focus, setFocus] = React.useState<boolean>(false);

  const [value, dispatchValue] = React.useReducer(
    (state: string, newValue: string) => {
      const [formattedWholeValue, decimalValue = "0"] = newValue.split(".");
      const significantValue = formattedWholeValue.replace(/,/g, "");
      const floatValue = parseFloat(
        significantValue + "." + decimalValue.slice(0, 2)
      );
      if (isNaN(floatValue) === false) {

        // you can dispatch to your redux store here - floatValue should be 
        // a number, that's well formed

        let n = new Intl.NumberFormat("en-EN", {
          minimumFractionDigits: 0,
          maximumFractionDigits: 2
        }).format(floatValue);

        if (newValue.includes(".") && !n.includes(".")) {
          return n + ".";
        }
        return n;
      }
      return "0";
    },
    ""
  );

  return (
    <>
      <div onClick={() => valueRef.current?.focus()} isFocused={focus}>
        <input
          type="text"
          pattern="d+(.d{2})?"
          value={value}
          onChange={(e) => dispatchValue(e.target.value)}
          ref={valueRef}
          onFocus={() => setFocus(true)}
          onBlur={() => setFocus(false)}
        />
        <div>USD</div>
      </div>
    </>
  );
};

export default function App() {
  return (
    <div className="App">
      <CurrencyInput />
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}
Related