title: How to prevent negative numbers and numbers above certain limit, and let the user loop among the available numbers, in an input field using keyevents?
body: <p>I have a reusable component called <strong>TimePickerComponent</strong> which I am using to display an input field where the user can put hours and minutes. I have some arrows that appears on hover to let the user going up or down with hours as well as another arrow for the minutes (I put in attachment the screenshot)</p>
  <p>For the minutes, if the user reach the 59 using the arrow-up and click again, the next number would be 00. While if the user uses the arrow-down and reach the number 00, the next value would be 60. So basically it loops. The same works with the hours, but from 0 to 24. With the arrows and onClick event everything works.</p>
  <p>The problem is that when I don't use the arrows and the user uses the <em>keyDown</em> event, the numbers go to minus infinite as well as when the user uses the <em>keyUp</em> event the numbers goes to infinite. So I am wondering if I should create a function that would overwrite this input field behaviour and if yes, how? I tried with the events but it did not work. This is my initial code working with the arrows but not with keyPress events, i put also in attachment the screenshot of the page section:</p>
  <pre><code>function TimePickerComponent({ hours, setHours, minutes, setMinutes }) {
  
  
    // INTERVAL STATES ARROWS
    const [showIntervalFirstHoursArrow, setShowIntervalFirstHoursArrow] =
      useState(false);
    const [showIntervalFirstMinutesArrow, setShowIntervalFirstMinutesArrow] =
      useState(false);
  
    // INCREMENTS/DECREMENTS HOURS INTERVALS
    const incrementFirstHour = () =&gt; {
      setHours((prevHours) =&gt; {
        // if there is nothing
        if (!prevHours || +prevHours &gt;= 24) {
          return '0';
        } else {
          return String(+prevHours + 1);
        }
      });
    };
  
    const decrementFirstHours = () =&gt; {
      setHours((prevHours) =&gt; {
        // if there is nothing
        if (!prevHours) {
          return '0';
        } else if (+prevHours &lt;= 0) {
          return '24';
        } else {
          const currentHours = String(+prevHours - 1);
          if (currentHours.length === 1) {
            return '0' + currentHours;
          }
          return currentHours;
        }
      });
    };
  
    // INCREMENTS/DECREMENTS MINUTES INTERVALS
    const incrementFirstMinutes = () =&gt; {
      setMinutes((prevMinutes) =&gt; {
        // if there is nothing
        if (!prevMinutes || +prevMinutes &gt;= 59) {
          return '00';
        } else {
          const currentMinute = String(+prevMinutes + 1);
          if (currentMinute.length === 1) {
            return '0' + currentMinute;
          }
          return currentMinute;
        }
      });
    };
    const decrementFirstMinutes = () =&gt; {
      setMinutes((prevMinutes) =&gt; {
        // if there is nothing
        if (!prevMinutes) {
          return '00';
        } else if (+prevMinutes &lt;= 0) {
          return '59';
        } else {
          const currentMinute = String(+prevMinutes - 1);
          if (currentMinute.length === 1) {
            return '0' + currentMinute;
          }
          return currentMinute;
        }
      });
    };
  
    return (
      &lt;Inputs&gt;
        &lt;Container&gt;
          &lt;Selection
            onMouseEnter={() =&gt; setShowIntervalFirstHoursArrow(true)}
            onMouseLeave={() =&gt; setShowIntervalFirstHoursArrow(false)}
          &gt;
            {showIntervalFirstHoursArrow &amp;&amp; (
              &lt;p className=&quot;icon&quot; onClick={incrementFirstHour}&gt;
                &lt;IoIosArrowUp /&gt;
              &lt;/p&gt;
            )}
            &lt;SquareInput
              type=&quot;number&quot;
              onChange={(e) =&gt; setHours(e.target.value)}
              value={hours}
            /&gt;
            {showIntervalFirstHoursArrow &amp;&amp; (
              &lt;p className=&quot;icon&quot; onClick={decrementFirstHours}&gt;
                &lt;IoIosArrowDown /&gt;
              &lt;/p&gt;
            )}
          &lt;/Selection&gt;
          &lt;p&gt;:&lt;/p&gt;
          &lt;Selection
            onMouseEnter={() =&gt; setShowIntervalFirstMinutesArrow(true)}
            onMouseLeave={() =&gt; setShowIntervalFirstMinutesArrow(false)}
          &gt;
            {showIntervalFirstMinutesArrow &amp;&amp; (
              &lt;p className=&quot;icon&quot; onClick={incrementFirstMinutes}&gt;
                &lt;IoIosArrowUp /&gt;
              &lt;/p&gt;
            )}
            &lt;SquareInput
              min=&quot;0&quot;
              type=&quot;number&quot;
              onChange={(e) =&gt; {
                if (e.target.value.split('').length &gt; 2) return;
                // if(e.target.value == 0) return;
                if (+e.target.value &gt; 60) {
                  return;
                  // setMinutes('0');
                } else if (+e.target.value &lt; 0) {
                  setMinutes('60');
                } else {
                  setMinutes(e.target.value);
                }
              }}
              value={minutes}
            /&gt;
            {showIntervalFirstMinutesArrow &amp;&amp; (
              &lt;p className=&quot;icon&quot; onClick={decrementFirstMinutes}&gt;
                &lt;IoIosArrowDown /&gt;
              &lt;/p&gt;
            )}
          &lt;/Selection&gt;
        &lt;/Container&gt;
      &lt;/Inputs&gt;
    );
  }
  
  // STYLES
  const Inputs = styled.div`
    display: flex;
    align-items: center;
  
    p {
      font-size: 0.8em;
      text-align: center;
    }
  `;
  const Container = styled.div`
    border: 1px solid #c5c5c5;
    border-radius: 10px;
    height: 40px;
    margin: 0 5px;
    display: flex;
    align-items: center;
  `;
  const Selection = styled.div`
    .icon {
      font-size: 1.2em;
      padding: 10px;
      cursor: pointer;
    }
  `;
  
  const SquareInput = styled.input`
    width: 50px;
    border: none;
    outline: none;
    font-size: 1.1em;
    text-align: center;
    ::-webkit-inner-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }
    ::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }
    /* /* Firefox */
    /* input[type=number] {
    -moz-appearance: textfield;
  } */
  `;
  
  export default TimePickerComponent;
  </code></pre>
  <p><a href="https://i.stack.imgur.com/wPyfC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/wPyfC.png" alt="enter image description here" /></a></p>