skip to Main Content

I’m trying to add commas to a text input as the user types.

  • User typing: 1234
  • Rendered Input value: 1,234

However, I’m encountering two issues.

  1. React doesn’t allow updating e.target.value before setState (https://react.dev/reference/react-dom/components/input#my-input-caret-jumps-to-the-beginning-on-every-keystroke)

  2. If I ignore React’s advice and update e.target.value directly, the cursor moves to the end even when typing in the middle of the text.

import {useState} from 'react';

const NumberInput = () => {
    const [value, setValue] = useState('');
    const handleChange = (event) => {
        const inputValue = event.target.value;
        setValue(
            inputValue.replace(/D/g, '').replace(/B(?=(d{3})+(?!d))/g, ',')
        );
    };

    return <input type="text" value={value} onChange={handleChange} />;
};

export default NumberInput;

Is there a good approach to adding commas in a controlled component? I would appreciate any suggestions or solutions. Thank you!

2

Answers


  1. Asking ChatGPT about this he provided the following approach, Please read the notice at the bottom since there is a catch and it might not be suitable for you

    const NumberInput = () => {
      const [value, setValue] = useState('');
      const inputRef = useRef(null);
    
      const handleChange = (event) => {
        const inputValue = event.target.value;
        const inputElement = inputRef.current;
    
        // Get cursor position
        const selectionStart = inputElement.selectionStart;
        const selectionEnd = inputElement.selectionEnd;
        const selectionLength = selectionEnd - selectionStart;
    
        // Remove non-digit characters and add commas
        const formattedValue = inputValue.replace(/D/g, '').replace(/B(?=(d{3})+(?!d))/g, ',');
    
        setValue(formattedValue);
    
        // Calculate new cursor position
        const newSelectionStart = selectionStart + (formattedValue.length - inputValue.length);
        const newSelectionEnd = newSelectionStart + selectionLength;
    
        // Set new cursor position
        setTimeout(() => {
          inputElement.setSelectionRange(newSelectionStart, newSelectionEnd);
        }, 0);
      };
    
      return <input ref={inputRef} type="text" value={value} onChange={handleChange} />;
    };
    

    it basically makes sure that the cursor is set in the right place after every user input, At first I thought it gets the job done perfectly, Though I noticed that it actually glitches when the user presses two buttons at nearly the same time, It’s unlikely that users will do that but if that’s a real concern you might need a different approach.

    Login or Signup to reply.
  2. your code look pretty, if you want to try more i’ll give you some option.

    1. Another solution :
    import React, { useState } from 'react';
    
    function NumberInput() {
      const [inputValue, setInputValue] = useState('');
    
      const handleInputChange = (event) => {
        const rawValue = event.target.value.replace(/D/g, ''); // Remove non-digit characters
        const formattedValue = Number(rawValue).toLocaleString();
        setInputValue(formattedValue);
      };
    
      return (
        <input type="text" value={inputValue} onChange={handleInputChange} />
      );
    }
    
    export default NumberInput;
    1. Use libary: https://www.npmjs.com/package/react-number-format
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search