skip to Main Content

I’m creating a reusable component that should be like this :

enter image description here

Problem: The increment/decrement buttons work fine, but when I click in the input field and type a number, nothing happens. Why?

Here is a minimal reproduced code example: Sandbox

Here is my code:

const InputCounter = ({ id, label, value }: NumericInputProps) => {
  const [count, setCount] = useState(value ?? 0);

  return (
    <div className="flex flex-col gap-2">
      <label htmlFor={id} className="text-sm font-bold text-neutral-700">
        {label}
      </label>

      <div className="flex w-fit items-center rounded border border-solid border-neutral-300">
        <button
          type="button"
          className="h-10 w-10 rounded border -m-px mr-0 border-solid border-neutral-300 bg-transparent focus:outline-none hover:cursor-pointer"
          onClick={() => setCount(count > 0 ? count - 1 : 0)}
        >
          <IconLess width={16} height={16} />
        </button>

        <input
          id={id}
          type="number"
          value={count}
          className="h-10 w-16 rounded border-none text-center text-base font-semibold focus:outline-none"
        />

        <button
          type="button"
          className="h-10 w-10 rounded border -m-px ml-0 border-solid border-neutral-300 bg-transparent focus:outline-none hover:cursor-pointer"
          onClick={() => setCount(count + 1)}
        >
          <IconPlus width={16} height={16} />
        </button>
      </div>
    </div>
  );

2

Answers


  1. you have to set the value in setCount on onChange, as you can see the below code, also I have update the code on sandbox

    <input
      id={id}
      type="number"
      value={String(count)}
      onChange={(e) => setCount(Number(e.target.value))}
      className="h-10 w-16 rounded border-none text-center text-base font-semibold 
      focus:outline-none"
    />
    
    Login or Signup to reply.
  2. It is because you are setting the value of number, but you are not hooking the change to the value of number, you need to consider using onChange on the number and try updating the value of number.

    Updated code with few optimizations would be :

    const InputCounter = ({ id, label, value }: NumericInputProps) => {
      const [count, setCount] = useState(value ?? 0);
    
      const handleInputChange = (event) => {
        const value = parseInt(event.target.value);
        setCount(isNaN(value) ? 0 : value);
      };
    
      const handleDecrement = () => {
        setCount((count) => Math.max(0, count - 1));
      };
    
      const handleIncrement = () => {
        setCount((count) => count + 1);
      };
    
      return (
        <div className="flex flex-col gap-2">
          <label htmlFor={id} className="text-sm font-bold text-neutral-700">
            {label}
          </label>
    
          <div className="flex w-fit items-center rounded border border-solid border-neutral-300">
            <button
              type="button"
              className="h-10 w-10 rounded border -m-px mr-0 border-solid border-neutral-300 bg-transparent focus:outline-none hover:cursor-pointer"
              onClick={handleDecrement}
            >
              <IconLess width={16} height={16} />
            </button>
    
            <input
              id={id}
              type="number"
              value={count}
              onChange={handleInputChange}
              className="h-10 w-16 rounded border-none text-center text-base font-semibold focus:outline-none"
            />
    
            <button
              type="button"
              className="h-10 w-10 rounded border -m-px ml-0 border-solid border-neutral-300 bg-transparent focus:outline-none hover:cursor-pointer"
              onClick={handleIncrement}
            >
              <IconPlus width={16} height={16} />
            </button>
          </div>
        </div>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search