188

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?

5
  • Never got this example to work. Do you managed to solve it any other way? Commented Jan 5, 2016 at 14:47
  • See also: stackoverflow.com/questions/40630918/… Commented Nov 1, 2017 at 13:17
  • Note that as of React Native 0.54, most of the answers suggested here are broken: github.com/facebook/react-native/issues/18874 (up to at least 0.56, which is the newest version at the time of writing). Commented Jul 25, 2018 at 18:24
  • 1
    @sumitkumarpradhan That blog post suggests setting the keyboard type to 'numeric' which doesn't actually prevent text input. You can copy paste anything you want into there. Commented Jul 11, 2019 at 15:42
  • 1
    I am using keyboardType='numeric' prop in TextInput to only show Numeric Keyboard (duh) and also replacing texts with regex text.replace(/[^0-9]/g, '') as suggested below to prevent anyone from pasting strings inside the TextInput. Is working fine so far on React Native v0.62 Commented Sep 26, 2020 at 7:06

24 Answers 24

183

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

Sign up to request clarification or add additional context in comments.

7 Comments

How can i allow only letters in the english alphabet using this method?
@CraZyDroiD just adjust the regex. If you only want to match A-Z, you'll need something like text.replace(/[^A-Za-z]/g, '')
Also pass keyboardType='numeric' prop to TextInput field.
it works fine, but there is little flickering can we overcame in any way
what about follow number? eg, 000.1? It might not be a valid number~
|
141

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 });
}

2 Comments

Is there anyway to prevent flickering?
Note, for "keyboardType", the value "numeric" seems to do the exact same thing as "number-pad" (tested on Android)
39

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

2 Comments

How can I set with country code.(i.e) can I able to set the country code with any props in text input component
Do you have a specific code to share, your answer is too general :(
35

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

1 Comment

This is nice, but it will not work if you have an attached physical keyboard.
33

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

1 Comment

The problem is if user is using pad and connect with physical keyboard, the software constrain keyboard might not work.
13

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
}

2 Comments

No need to create these first two functions, you can just use: validations(value: string) { return /0/.test(value) && /^\d+$/.test(value) ? this.setState({ numColumns: value }) : false; }
@FrederikoCesar Take a peek at single responsibility principle
10

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.

1 Comment

that's more efficient way, it should be followed instead of looping method
10
const [text, setText] = useState('');

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

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

This should save from physical keyboards

3 Comments

thanks, i suggest to replace if(+text) with if (+text || text == "") to allow empty input
Op specifically said they don't want to allow "." in the input.
The +text for changing it to a number was awesome, thanks.
8

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

5 Comments

This should be a comment and not an answer
Apologise that I don't have enough reputation to comment on the question so I end up with an answer, hopefully to bring attention to people seeking out workable solutions.
Fair point. I see that one would need 50 reputation to comment. Sadly, I can't remove that restriction, but I can give you 10 reputation and hopefully remove some of the restrictions.
take it 10 more to get comment provision... Cheers @Wing
Thanks :) @VenkateshSomu
6

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, '') 
    });
}

Comments

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

3 Comments

!/^[0-9]+$/.test('123456askm') it will check input string is numeric or not .test(Your Value )
Hi, please expand on your answer as to why this would be a solution to OP's issue. This will help OP and future visitors of the site. Thanks!
This doesn't answer the question at all.
4
<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 });
    }
}

4 Comments

Your solution, although solving my problem, produces warning: "This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property 'type' on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See fb>react-event-pooling for more information." I don't know what to do with this. Can you help?
@Mike some event might causing this, can you share your component code via jsfiddle or rnplay.org
I solved that shortly after commenting here, but unfortunately can figure what was the problem.
using a regex would be a smarter choice
4

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.

1 Comment

This is nice, except I cannot get any digits after the decimal point? It would be nice to allow a negative as well, e.g. -3.14
3

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.

Comments

2

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],
    });
}

Comments

2

You can remove non numeric characters using regex

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

Comments

2

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 });

}

Comments

2

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.

Comments

2

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('');

Comments

1

I've created a component that solves this problem:

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

Comments

1

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}
        />

Comments

1

You can achieve this by using keyboardType="numeric" // This sets the keyboard to numeric or Regular Expressions

import React, { useState } from 'react';
import { View, TextInput, StyleSheet } from 'react-native';

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

  const handleTextChange = (inputText) => {
    // Remove any non-numeric characters using regular expression
    const numericText = inputText.replace(/[^0-9]/g, '');
    setText(numericText);
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        value={text}
        onChangeText={handleTextChange}
        keyboardType="numeric" // This sets the keyboard to numeric
        placeholder="Enter numeric value"
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  input: {
    width: 200,
    height: 40,
    borderWidth: 1,
    borderColor: 'gray',
    paddingHorizontal: 10,
  },
});

export default NumericTextInput;

Comments

0

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.

Comments

-1

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)
    }

1 Comment

OP specifically mentions that as a non-solution in the question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.