How to prevent user from entering negative number in react?

Viewed 10161

I want to restrict users from entering negative values. I am using min = "0". With this i can restrict users from decrementing to 0, i.e, users can only decrement value till 0. But they are able to type "-". How to prevent in react js.

https://codesandbox.io/s/react-input-example-forked-xnvxm?file=/src/index.js

<input
   type="number"
   min="0"
   step="1"                        
   onChange={this.handleChange}                        
   className="w-100"
   value= "1"
   />
6 Answers

You can add an onKeyPress listener to the input element and that will be triggered before the onChange and call a function that will prevent default behaviour when the minus button is pressed.

const preventMinus = (e) => {
    if (e.code === 'Minus') {
        e.preventDefault();
    }
};

<input               
  type="number"
  min="0"
  onKeyPress={preventMinus}
/>

Note that this will still allow negative values to be pasted into the input. For this, you can add an onPaste listener and check the clipboard data to see if it's negative and prevent the default behaviour.

const preventPasteNegative = (e) => {
    const clipboardData = e.clipboardData || window.clipboardData;
    const pastedData = parseFloat(clipboardData.getData('text'));

    if (pastedData < 0) {
        e.preventDefault();
    }
};

<input               
  type="number"
  min="0"
  onPaste={preventPasteNegative}
  onKeyPress={preventMinus}
/>

Handling Empty Input & Negative Numbers

// Converting App into Class-Component
class App extends React.Component {
  // Set State
  constructor(props) {
    super(props);
    this.state = {
      number: ""
    };
  }

  render() {
    return (
      <div className="App">
        <input
          type="number"
          min="0"
          step="1"
          onChange={(e) => {
            let val = parseInt(e.target.value, 10);
            if (isNaN(val)) {
              this.setState({ number: "" });
            } else {
              // is A Number
              val = val >= 0 ? val : 0;
              this.setState({ number: val });
            }
          }}
          className="w-100"
          // Assign State
          value={this.state.number}
        />
      </div>
    );
  }
}

You can use a regex to validate the input before setting the state of your input and sync the input value with your state value.


<input
  type="number"                  
  onChange={this.handleChange}                        
  className="w-100"
  value= {this.state.inputVal}
/>

validateNumber = (value) => {
  //true for digits only.
  const regex = /^[0-9]+$/
  return regex.test(value);
}
handleChange = ({target}) => {
  const {name,value} = target;
  const {inputVal} = this.state;

  if(value === '') {
    return this.setState({inputVal:''});
  }

  if(this.validateNumber(value)) {
    this.setState({inputVal:value})
  } else {
    this.setState({inputVal:inputVal})
  }
}

Use some local component state to hold the input's value and use Math.max(0, value) to ensure the value prop/attribute is a non-negative value. The input's value will be a string in the onChange handler so remember to coerce it back to a number value for state.

function App() {
  const [value, setValue] = React.useState(0);
  return (
    <div className="App">
      <label>
        Try entering a negative value
        <input
          type="number"
          min="0"
          step="1"
          className="w-100"
          value={value && Math.max(0, value)}
          onChange={e => setValue(e.target.value ? Number(e.target.value) : e.target.value)}
        />
      </label>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

You can filter out input value inside handlechange. Something like this:

const App = () => {
  const [value, setValue] = useState("");

  const handleChange = (e) => {
    if (!isNaN(e.target.value)) {
      setValue(e.target.value);
    }
  };
  return (
    <div className="App">
      <input
        type="text"
        value={value}
        onChange={handleChange}
        className="w-100"
      />
    </div>
  );
};

Here is the demo: https://codesandbox.io/s/react-input-example-forked-kr2xc?file=/src/index.js

Other solutions weren't working for me (I could input negative number from scrolling mouse wheel or trackpad), so I made a kind of hardcoded method:

onChange={function (event) {
  if (value > 0 || event.target.valueAsNumber >= 0) {
    setValue(event.target.valueAsNumber);
  }
}}
Related