79674064

Date: 2025-06-21 00:57:58
Score: 0.5
Natty:
Report link

Many answers don't work in some scenarios and some introduce unneeded useEffect while also not working in all cases.

The defaultValue doesn't work for cases where the field is controlled, which is often needed when state is controlled and updated by upstream state.

In particular, when typing fast the timeout solutions don't work. (The answers with setTimeout or useEffect don't work when the user types quickly)

The Promise solution in one answer works well, and it is simple and clean.

The minimal code for the Promise solution that works regardless of typing speed using a controlled component:

<input
  value={value}
  onChange={async (event) => {
    const inputElement = event.target;
    setValue(inputElement.value);
    const { selectionStart, selectionEnd } = inputElement;
    /**
     * This works correctly, even if the user types quickly. (setTimeout does not)
     */
    await Promise.resolve().then(() => {
      inputElement.setSelectionRange(selectionStart, selectionEnd);
    });
  }}
/>

https://codesandbox.io/p/sandbox/qxg8k9?file=%2Fsrc%2FApp.js%3A1%2C1

For the original question, input type="number" does not support setSelectionRange, so many solutions to this question don't work if using that type. The only one that can is defaultValue, but that doesn't work if other code updates the state. Recommend using type="text" and convert to number outside of form.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange

The element must be of one of the following input types: password, search, tel, text, or url.

Reasons:
  • Blacklisted phrase (1.5): any solution
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: jazeee