React Native TextInput that only accepts numeric characters
React NativeReact 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
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:
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.