React number input

Creating a react number input control is a very simple task. It is very useful when you work on large project to keep the form development code cleaner rather implement the same logic everywhere. Before you begin you may want to setup react environment please refer to my article how to setup react environment. Lets create a typescript class and render a simple input textbox as follows;

import * as React from 'react';

export class NumberTextBox extends React.Component{
    constructor(props){
        super(props)
    }

    render(){
        return <input type="text"/>
    }
}
export default NumberTextBox;

Now create a app.tsx file and import the class you created into it as follows;

import * as React from 'react';
import * as ReactDom from 'react-dom';
import NumberTextBox from '../app/with-classes/number-text-box';
ReactDom.render(<NumberTextBox/>,document.getElementById('app'));

Import your compiled bundle into an index.html file and open it on your browser. You will see the following output.

initial react input text box

Let’s declare react number input props. Props is required to expose what properties users can set and what function or events that react number input can return.

How to define react number input control props?

React best practise is to create interfaces for both state and props. That will allow syntactic sugar as well as less compile time errors. We can create a new typescript file called number-text-ref.ts to hold reference details related to number text box.

Lets declare some basic props interface called InputProps as follows;

export interface InputProps{
    type?:string;
    name?:string;
    value?:number;
    className?:string;
    onChange?:Function;
}

The question mark(?) in front of each property make sure those properties are optional.

How to use the interfaces for mapping props in a typescript class component.

import * as React from 'react';

export class NumberTextBox extends React.Component<InputProps,null>{
    constructor(props){
        super(props)
    }

    render(){
        return <input type="text"/>
    }
}
export interface InputProps{
    type?:string;
    name?:string;
    value?:number;
    className?:string;
    onChange?:Function;
}
export default NumberTextBox;

How to make react number input control accept only numbers?

You can make sure react number input control only accept numbers by handling keypress event handler of the input. Event handlers always gives the key code when users type something. By observing the key code we can only allow numbers discard the rest.

Following code demonstrate how filter numbers using keypress event;

onKeyPress={(event)=>{
    var cVal = event.target.value;
    //allow only numbers and decimal point
    if (event.which < 48 || event.which > 57) {
        if (event.which != 46)
            event.preventDefault();
    } 
            
}}

What the above function is doing, it compare ASCII codes between 48 – 57 where the normal numbers are sitting in. Also allowing the decimal place too. Save code and refresh your browser and try to enter anything other than numbers, text box does not allow anthing other than numbers. But this number box has minor glitch in it, i.e users can enter multiple decimal points.

How to stop entering multiple decimal points?

Prevent entering multiple decimal points, we need to add a new property into our props called maxdecimalplaces. Two things to take care, if there are no decimal places react number control should not accept decimal point, otherwise only a single decimal point. As you can see if you don’t specify a value or if set 0 or null as maxdecimalplaces the control won’t allow users to enter decimal places. If you set it to a number greater than zero control should allows a single decimal place.

we have manage to stop entering multiple decimal points, but users can enter any number of decimal places. How we can stop multiple decimal places, add the following lines of code into keypress event.

//prevent exceeding number of decimal places      
    if(dec!=-1){
        //reading the decimal places  count
        var decPlaces=cVal.substring(dec+1,cVal.length).length;
        //compare it with props value
        if(decPlaces==this.props.maxdecimalplaces){
            event.preventDefault();
        }
    } 

What above code does, if decimal point is present count the number of decimal place values against the props value and prevent entering any more decimal place values.

How to stop copying and pasting?

Moment you expose your form controls to external users, never know what they will do. Sometime users copy and paste values. When copying and pasting, keypress event does not trigger. Therefore none of the validations
will work, unless we handle onPaste event of the input control explicitly in such scenario.

users can copy and paste wrong input values

By adding following code snippet we can prevent the issue when users copying and pasting. This will help to prevent entering malicious characters too.

onPaste={(e)=>{
    e.preventDefault();
    return false;
}}  

Now refresh your browser and try to copy and paste the same value, our control does not allow users to past values. Now you reactjs number textbox control code would look as follows;

import * as React from 'react';
import { INProps } from './number-text-ref';

export class NumberTextBox extends React.Component<INProps,null>{
    constructor(props){
        super(props)
    }

    render(){
        return <input 
        type={this.props.type}
        onKeyPress={(event)=>{
            var cVal = event.target.value;
            var dec=cVal.indexOf('.');
            //allow only numbers and decimal point
            if (event.which < 48 || event.which > 57) {
                if (event.which != 46)
                    event.preventDefault();
            }

            //read max decimal places 
            var maxDecimalPlaces = this.props.maxdecimalplaces > 0 ? this.props.maxdecimalplaces - 1 : 0;
            //no decimal places
            if (maxDecimalPlaces == 0) {
                if (event.which == 46) {
                    //not allowing decimal places
                    event.preventDefault();
                }
            } else {
                //allowing only one time
                if (event.which == 46 && dec != -1) {
                    event.preventDefault(); // prevent if there is already a dot
                }
            } 

            //prevent exceeding number of decimal places      
            if(dec!=-1){
                //reading the decimal places  count
                var decPlaces=cVal.substring(dec+1,cVal.length).length;
                //compare it with props value
                if(decPlaces==this.props.maxdecimalplaces){
                    event.preventDefault();
                }
            }             
        }}
        onPaste={(e)=>{
            e.preventDefault();
            return false;
        }}
        />
    }
}
export default NumberTextBox;

Some examples of react number textbox

You can use this control many different ways. Following examples show you three different ways of using the react number textbox.

Lets change your app.tsx code as follows;

import * as React from 'react';
import * as ReactDom from 'react-dom';

import NumberTextBox from '../app/with-classes/number-text-box';

export class ExampleNumbers extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return <table>
        <tbody>
            <tr>
                <td>Only numbers</td>
                <td>
                    <NumberTextBox 
                        type={"text"} 
                        maxdecimalplaces={0}
                        placeholder={"Please enter numbers only"}
                        />
                </td>                
            </tr>
            <tr>
            <td>Numbers with 2 Decimals</td>
                <td>
                    <NumberTextBox 
                        type={"text"} 
                        maxdecimalplaces={2}
                        placeholder={"Please enter numbers with decimal"}
                        />
                </td>
            </tr>
            <tr>
            <td>Enter percentage</td>
                <td>
                    <NumberTextBox 
                        type={"text"} 
                        maxdecimalplaces={2}
                        maxLength={5}
                        placeholder={"Please enter numbers with decimal"}
                        />
                </td>
            </tr>
        </tbody>
    </table>
    }
}
    
ReactDom.render(<ExampleNumbers/>,document.getElementById('app'));

Above code shows different ways of using this number control without implementing the same logic everywhere. In the first instance we user the control as integer. Second instance as a decimal number with 2 decimal places. Last instance is how to use it as percentage.

React number input examples
react number input

Next article I will show you how to build the same control using react hooks and implement single responsibility principle.

You can download code from here