How to setValue that also allows for direct entry of a decimal point with Input in Chakra UI?

35 views Asked by At

I take a reference from official document

https://chakra-ui.com/docs/components/number-input

The example user can click inc and dec icon to change value also directly input in the text box.

import {
  ChakraProvider,
  Stack,
  HStack,
  Button,
  Input,
  useNumberInput
} from "@chakra-ui/react";

  const { getInputProps, getIncrementButtonProps, getDecrementButtonProps } =
    useNumberInput({
        step: 0.01,
        defaultValue: 0.5,
        min: 0.01,
        max: 1.0,
        precision: 2,
    })

  const inc = getIncrementButtonProps()
  const dec = getDecrementButtonProps()
  const input = getInputProps()

  return (
    <Stack>
    <HStack maxW='320px'>
      <Button {...inc}>+</Button>
      <Input {...input} />
      <Button {...dec}>-</Button>
    </HStack>
    </Stack>
  );

Then I want to change the value with other buttons, so I try to use setState, After some attempts, I found that I couldn't use defaultValue in useNumberInput, so I use value and onChange.

const [limiInputValue, setLimitInputValue] = useState(0.5);

  const { getInputProps, getIncrementButtonProps, getDecrementButtonProps } =
    useNumberInput({
        step: 0.01,
        // defaultValue: limiInputValue,
        min: 0.01,
        max: 1.0,
        precision: 2,
        value: limiInputValue,
        onChange: value => {
          console.log('onChange value', value);
          setLimitInputValue(Number(value));
        },
    })

  const inc = getIncrementButtonProps()
  const dec = getDecrementButtonProps()
  const input = getInputProps()

  return (
    <Stack>
    <HStack maxW='320px'>
      <Button {...inc}>+</Button>
      <Input {...input} />
      <Button {...dec}>-</Button>
    </HStack>
    <Button onClick={() =>  setLimitInputValue(0.25)}>Set</Button>
    </Stack>
  );

Everything is fine, but I have a problem is user can't type decimal point in Input directly.

How to fix it ?

Here is my sandbox example:

https://codesandbox.io/p/devbox/twk7v6?file=%2Fsrc%2Findex.tsx%3A19%2C18

1

There are 1 answers

1
Hashan Hemachandra On BEST ANSWER

The issue you are experiencing is, In your onChange function, you are converting the value to a number immediately with Number(value). This can create problems when typing decimal numbers because as soon as you type the decimal point (without following numbers), Number(value) will return 0 if the input is not a valid number, which effectively removes the decimal point from the input.

To fix this, Allow the user to input decimals by not immediately converting the input value to a number inside the onChange handler. Only update the limiInputValue state if the new value is a valid number within the specified range.

Follow the below code :-

onChange: value => {
    console.log('onChange value', value);
    // Check if the value is a valid floating point number or if it's an empty string
    if (value === '' || (!isNaN(value) && value[value.length - 1] !== '.')) {
        // Update the state only if the value is within the min and max range or it's an initial input
        const numericValue = parseFloat(value);
        if (numericValue >= 0.01 && numericValue <= 1.0 || value === '') {
            setLimitInputValue(numericValue);
        }
    } else if (value[value.length - 1] === '.') {
        // Allow the user to type the decimal point
        setLimitInputValue(value);
    }
},