React Native TextInput that only accepts numeric characters

React Native

React Native Problem Overview


I need to have a React Native TextInput component that will only allow numeric characters (0 - 9) to be entered. I can set the keyboardType to numeric which almost gets me there for input except for the period (.). However this does nothing to stop pasting non-numeric characters into the field.

What I've come up with so far is to use the OnChangeText event to look at the text entered. I remove any non-numeric characters from the text. Then put the text in a state field. Then update the TextInput through it's Value property. Code snippet below.

<TextInput 
  style={styles.textInput}
  keyboardType = 'numeric'
  onChangeText = {(text)=> this.onChanged(text)}
  value = {this.state.myNumber}
/> 

onTextChanged(text) {
  // code to remove non-numeric characters from text
  this.setState({myNumber: text})
}

This seems to work but it seems like a hack. Is there another way to do this?

React Native Solutions


Solution 1 - React Native

Using a RegExp to replace any non digit is faster than using a for loop with a whitelist, like other answers do.

Use this for your onTextChange handler:

onChanged (text) {
    this.setState({
        mobile: text.replace(/[^0-9]/g, ''),
    });
}

Performance test here: https://jsperf.com/removing-non-digit-characters-from-a-string

Solution 2 - React Native

You can do it like this. It will only accept numeric values, and limit to 10 numbers as your wish.

<TextInput 
   style={styles.textInput}
   keyboardType='numeric'
   onChangeText={(text)=> this.onChanged(text)}
   value={this.state.myNumber}
   maxLength={10}  //setting limit of input
/>

You can see the entered value by writing the following code in your page:

{this.state.myNumber}
 

In the onChanged() function the code look like this:

onChanged(text){
    let newText = '';
    let numbers = '0123456789';
  
    for (var i=0; i < text.length; i++) {
        if(numbers.indexOf(text[i]) > -1 ) {
            newText = newText + text[i];
        }
        else {
            // your call back function
            alert("please enter numbers only");
        }
    }
    this.setState({ myNumber: newText });
}

I hope this is helpful to others.

Solution 3 - React Native

That is the correct way to do it till such a component (or attribute on the TextInput) is specifically developed.

The web has the ‘number’ type for the input element, but that is web based and react-native does not use a web view.

You could consider to create that input as a react component on it’s own (maybe call NumberInput): that’ll enable you to reuse it or maybe even open source it since you can create many TextInputs that has different value filters/checkers.

The downside to immediate correction is to ensure correct feedback is given to the user as to prevent confusion as to what happened to his value

Solution 4 - React Native

React Native TextInput provides keyboardType props with following possible values : default number-pad decimal-pad numeric email-address phone-pad

so for your case you can use keyboardType='number-pad' for accepting only numbers. This doesn't include '.'

so,

<TextInput 
  style={styles.textInput}
  keyboardType = 'number-pad'
  onChangeText = {(text)=> this.onChanged(text)}
  value = {this.state.myNumber}
/>

is what you have to use in your case.

for more details please refer the official doc link for TextInput : https://facebook.github.io/react-native/docs/textinput#keyboardtype

Solution 5 - React Native

First Solution

You can use keyboardType = 'numeric' for numeric keyboard.

  <View style={styles.container}>
        <Text style={styles.textStyle}>Enter Number</Text>
        <TextInput
          placeholder={'Enter number here'}
          style={styles.paragraph}
          keyboardType="numeric"
          onChangeText={value => this.onTextChanged(value)}
          value={this.state.number}
        />
      </View>

In first case punctuation marks are included ex:- . and -

Second Solution

Use regular expression to remove punctuation marks.

 onTextChanged(value) {
    // code to remove non-numeric characters from text
    this.setState({ number: value.replace(/[- #*;,.<>\{\}\[\]\\\/]/gi, '') });
  }

Please check snack link

https://snack.expo.dev/@vishaldhanotiya/numeric-keyboard

Solution 6 - React Native

Only allow numbers using a regular expression
<TextInput 
  keyboardType = 'numeric'
  onChangeText = {(e)=> this.onTextChanged(e)}
  value = {this.state.myNumber}
/> 

onTextChanged(e) {
  if (/^\d+$/.test(e.toString())) { 
    this.setState({ myNumber: e });
  }
}
You might want to have more than one validation
 
<TextInput 
  keyboardType = 'numeric'
  onChangeText = {(e)=> this.validations(e)}
  value = {this.state.myNumber}
/> 

numbersOnly(e) {
    return /^\d+$/.test(e.toString()) ? true : false
}

notZero(e) {
    return /0/.test(parseInt(e)) ? false : true
}

validations(e) {
    return this.notZero(e) && this.numbersOnly(e)
        ? this.setState({ numColumns: parseInt(e) })
        : false
}

Solution 7 - React Native

Function to validate input:

validateInputs(text, type) {
let numreg = /^[0-9]+$/;
  if (type == 'username') {
    if (numreg.test(text)) {
      //test ok
    } else {
      //test not ok
    } 
  }
}



<TextInput
   onChangeText={text => this.validateInputs(text, 'username')}
/>

I hope this is helpful.

Solution 8 - React Native

A kind reminder to those who encountered the problem that "onChangeText" cannot change the TextInput value as expected on iOS: that is actually a bug in ReactNative and had been fixed in version 0.57.1. Refer to: https://github.com/facebook/react-native/issues/18874

Solution 9 - React Native

const [text, setText] = useState('');

const onChangeText = (text) => {
  if (+text) {
    setText(text);
  }
};

<TextInput
  keyboardType="numeric"
  value={text}
  onChangeText={onChangeText}
/>

This should save from physical keyboards

Solution 10 - React Native

if (!/^[0-9]+$/.test('YourString')) {
  console.log('Enter Only Number');
} else {
    console.log('Success');
}

Solution 11 - React Native

<TextInput autoCapitalize={'none'} maxLength={10} placeholder='Mobile Number'  value={this.state.mobile} onChangeText={(mobile) => this.onChanged(mobile)}/>

and onChanged method :

onChanged(text){
   var newText = '';
   var numbers = '0123456789';
   if(text.length < 1){
     this.setState({ mobile: '' });
   }
   for (var i=0; i < text.length; i++) {
        if(numbers.indexOf(text[i]) > -1 ) {
             newText = newText + text[i];
        }
        this.setState({ mobile: newText });
    }
}

Solution 12 - React Native

I had the same problem in iOS, using the onChangeText event to update the value of the text typed by the user I was not being able to update the value of the TextInput, so the user would still see the non numeric characters that he typed.

This was because, when a non numeric character was pressed the state would not change since this.setState would be using the same number (the number that remained after removing the non numeric characters) and then the TextInput would not re render.

The only way I found to solve this was to use the keyPress event which happens before the onChangeText event, and in it, use setState to change the value of the state to another, completely different, forcing the re render when the onChangeText event was called. Not very happy with this but it worked.

Solution 13 - React Native

Here is my other simple answer to accept only numbers in the text box using Regular Expressions.

onChanged(text){
    this.setState({ 
         myNumber: text.replace(/[^0-9]/g, '') 
    });
}

Solution 14 - React Native

I wrote this function which I found to be helpful to prevent the user from being able to enter anything other than I was willing to accept. I also used keyboardType="decimal-pad" and my onChangeText={this.decimalTextChange}

  decimalTextChange = (distance) =>
{
    let decimalRegEx = new RegExp(/^\d*\.?\d*$/)
    if (distance.length === 0 || distance === "." || distance[distance.length - 1] === "."
        && decimalRegEx.test(distance)
    ) {
        this.setState({ distance })
    } else {
        const distanceRegEx = new RegExp(/^\s*-?(\d+(\.\d{ 1, 2 })?|\.\d{ 1, 2 })\s*$/)
        if (distanceRegEx.test(distance)) this.setState({ distance })
    }
}

The first if block is error handling for the event the user deletes all of the text, or uses a decimal point as the first character, or if they attempt to put in more than one decimal place, the second if block makes sure they can type in as many numbers as they want before the decimal place, but only up to two decimal places after the point.

Solution 15 - React Native

Using a RegExp to replace any non digit. Take care the next code will give you the first digit he found, so if user paste a paragraph with more than one number (xx.xx) the code will give you the first number. This will help if you want something like price, not a mobile phone.

Use this for your onTextChange handler:

onChanged (text) {
    this.setState({
        number: text.replace(/[^(((\d)+(\.)\d)|((\d)+))]/g,'_').split("_"))[0],
    });
}

Solution 16 - React Native

You can remove non numeric characters using regex

onTextChanged (text) {
    this.setState({
        myNumber: text.replace(/\D/g, ''),
    });
}

Solution 17 - React Native

I've created a component that solves this problem:

https://github.com/amirfl/react-native-num-textinput

Solution 18 - React Native

For Decimal /Floating point number only try this

    onChangeMyFloatNumber(text){
let newText = '';
let numbers = '0123456789.';

for (var i=0; i < text.length; i++) {
    if(numbers.indexOf(text[i]) > -1 ) {
        newText = newText + text[i];
        if(text[i]=="."){
          numbers = '0123456789'
        }
    }
    else {
        // your call back function
        alert("please enter numbers only");
    }
}
this.setState({ MyFloatNumber: newText });

}

Solution 19 - React Native

In case anyone is looking for solution that allows to use numeric keyboard but also validates input to allow only one decimal point then below is what I wrote to accomplish that. I also wanted to have comma(,) replaced with dot(.) as that's the way I'm saving it to database but you can remove that - it's optional.

const [decimalInput, setDecimalInput] = useState('')
const validator = /^[+-]?\d*(?:[.,]\d*)?$/;

function onNumberInputChange(text){
        if (validator.test(text)){
            text = text.replace(",",".") //this is optional
            setDecimalInput(text);
        }
        else{
		    //this will remove the last character as it didn't succeed validation
            setDecimalInput(text.substring(0, text.length - 1));
        }
    }

and text input component initialization like this:

<TextInput
                style={{textAlign: 'center'}}
                value = {decimalInput}
                onChangeText={(text) => {
                  setDecimalInput(text);
                  onNumberInputChange(text);
                }}
                placeholder={"type decimal value here..."}
                keyboardType="numeric"
                placeholderTextColor="#ccc">
</TextInput>

Maybe some of you will need same approach.

Solution 20 - React Native

if you add following lines then it will open number-pads only not characters-pads when you start typing:

 <TextInput
          placeholder="Enter Mobile No."
          onChangeText={setMobileNumber}
          value={mobileNumber}
          keyboardType="number-pad"
          maxLength={12}
        />

Solution 21 - React Native

i think,

onChangeText((val:string) => 
    isNaN(Number(val))
       ? val.substr(0, val.length - 1)
       : val
)
// 0     > true
// 0.    > true
// 0.3   > true
// -     > false
// .     > false
// 0.4-  > false
// -1.3  > true

this code will be check "is this a not a number?" and, if last char is wrong delete last word.

Solution 22 - React Native

change your key board type to numeric

<TextInput
onChangeText={this.onChangeText}
 keyboardType={"numeric"}
/>

then replace dot with space

onChangeText=(value)=>{
    let text = value.replace(".", '');
              if (isNaN(text)) {
                // Its not a number
                return
              }
    
    console.log("text",text)
    }

Solution 23 - React Native

If you are using hooks:

<TextInput
onChangeText={text=> setMyNumber(text?.replace(/[^0-9]/g, ''))}
....
/>

assuming the text is initialise using useState hook

const [myNumber,setMyNumber]=React.useState('');

Solution 24 - React Native

How about

onChangeText={(val) => {  
     if(!isNaN(val)){
       //setValue()
     }
  }
keyboardType="numeric"

This will check if the number is not, not a number, and only then will it set text.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTerryView Question on Stackoverflow
Solution 1 - React NativeJake TaylorView Answer on Stackoverflow
Solution 2 - React NativeVenkatesh SomuView Answer on Stackoverflow
Solution 3 - React NativeTjorriemorrieView Answer on Stackoverflow
Solution 4 - React NativeGanesh KrishnaView Answer on Stackoverflow
Solution 5 - React NativeVishal DhanotiyaView Answer on Stackoverflow
Solution 6 - React NativejasonleonhardView Answer on Stackoverflow
Solution 7 - React NativeAbdul Karim KhanView Answer on Stackoverflow
Solution 8 - React NativeWingView Answer on Stackoverflow
Solution 9 - React NativeZyfar BektashovView Answer on Stackoverflow
Solution 10 - React NativeANKIT DETROJAView Answer on Stackoverflow
Solution 11 - React NativeBheru Lal LoharView Answer on Stackoverflow
Solution 12 - React NativeGustavo FrancoView Answer on Stackoverflow
Solution 13 - React NativeVenkatesh SomuView Answer on Stackoverflow
Solution 14 - React NativeAndrew M YassoView Answer on Stackoverflow
Solution 15 - React NativeDaniel Jose Padilla PeñaView Answer on Stackoverflow
Solution 16 - React NativeAnoopView Answer on Stackoverflow
Solution 17 - React NativeamirflView Answer on Stackoverflow
Solution 18 - React Nativeabinthomas12914View Answer on Stackoverflow
Solution 19 - React Nativetommy_keyView Answer on Stackoverflow
Solution 20 - React NativesherkhanView Answer on Stackoverflow
Solution 21 - React NativesoftcornView Answer on Stackoverflow
Solution 22 - React NativemaddyView Answer on Stackoverflow
Solution 23 - React NativeFortuneCookieView Answer on Stackoverflow
Solution 24 - React Nativesj_959View Answer on Stackoverflow