Shalitha Suranga Programmer | Author of Neutralino.js and Jerverless

Implementing react-input-mask for web apps

5 min read 1417

Implementing react-input-mask for web apps

Modern web applications accept various user inputs: mouse clicks, screen tap and keyboard events, gestures, audio, and files. Almost all web applications use keyboard events to capture detailed user input data. In other words, users can enter required data into typical web applications using their devices’ keyboards. For example, a user can enter a name, phone number, postal code, and email address during a particular web application’s registration process, and that information is then communicated to the backend.

Every user is different. They may have unique practices when it comes to form-filling, and they often try to use various formats in input fields. If a particular web application displays a raw text input field to capture a phone number, for example, the user may face several usability issues, such as not being able to predict the input field’s accepted format when they’re typing.

To avoid these types of issues, you can use input masks to provide user-friendly constraints for a particular user input field. In this article, I’ll explain how you can use input masking in your React applications.

What is input masking?

In user experience (UX) design, an input mask refers to a string template that is created based on a specific input format to prevent transcription errors. If the user tries to enter an invalid character, the masked input element blocks the invalid keystroke. For example, users won’t be able to enter English letters in a masked phone number field.

Frontend developers can use input masks to help ensure clean and valid user inputs are sent to their web application backends. At the same time, input masks motivate users to enter clean, correct inputs.

Input masking in React applications

There are several libraries that we can use to create input masks in React. The react-input-mask library is the most popular one, and it offers a very flexible API for developers. As a bonus, its behavior follows a UX-friendly design pattern.

First, install the react-input-mask npm package to create input masks in your React application.

npm install react-input-mask --save

Now, let’s try to create a simple masked input box for a phone number to check whether or not the library works. Add the following code into your App.js file or component.

import { useState } from 'react';
import InputMask from 'react-input-mask';
function PhoneInput(props) {
  return (
    <InputMask 
      mask='(+1) 999 999 9999' 
      value={props.value} 
      onChange={props.onChange}>
    </InputMask>
  );
}
function App() {
  const [phone, setPhone] = useState('');
  const handleInput = ({ target: { value } }) => setPhone(value);
  return (
    <div>
      <PhoneInput 
        value={phone} 
        onChange={handleInput}>
      </PhoneInput>
      <div style={{paddingTop: '12px'}}>Phone: {phone}</div>
    </div>
  );
}
export default App;

If you start the React development server with npm start or yarn start, you will see a masked input to enter a standard USA phone number (starting with the +1 dialing code), as shown below:

A simple example for masked input in React
A simple example for masked input in React.

We implemented a reusable component to accept phone numbers with the library’s InputMask component. The library’s generic mask component responds to the following React props:

We made a custom demo for .
No really. Click here to check it out.

  • mask: a template of the user input with predefined special characters — 9 for matching a number, a for a letter, and * for either a number or a letter
  • maskChar: this character can be used to fill the missing part of the input string; the default value is _ (underscore)
  • formatChars: you can change the default characters and regular expressions used for masking (in the mask property) by changing this property
  • alwaysShowMask: the library usually shows the mask when the user focuses on the masked input; set this property to true if you always want to show the mask

Like any other typical input element, we can use the onChange event to change the component state based on user inputs.

Basic react-input-mask examples

The input masking concept can be used in many different scenarios to enhance the user-friendliness of web applications. Check the following basic masking examples.

4-digit PIN

function PINInput(props) {
  return (
    <InputMask 
      mask='9999' 
      value={props.value} 
      onChange={props.onChange}
      placeholder='Enter PIN'>
    </InputMask>
  );
}

Google-style OTP

function GoogleOTP(props) {
  return (
    <InputMask 
      mask='G-999999' 
      maskChar={null}
      value={props.value} 
      onChange={props.onChange}>
    </InputMask>
  );
}

Standard credit card

function CreditCardInput(props) {
  return (
    <InputMask 
      mask='9999 9999 9999 9999' 
      value={props.value} 
      onChange={props.onChange}>
    </InputMask>
  );
}

Advanced react-input-mask examples

The above examples use built-in regular expressions for masking. For example, the four-digit PIN’s mask uses 9 to match digits.

However, we cannot implement every masking rule with these predefined regular expressions. In other words, we need to define custom masking characters with different regular expressions. In some scenarios, we also need to have dynamic masks, where the user’s input directs the constraints of subsequent characters they enter in the field.

Below, we’ll look at some advanced examples that use custom masking characters and conditional masks.

A custom product code

Assume that you need to implement a mask to capture a valid product code in a grocery store management app written in React. Let’s define the rules for a valid product code as such:

  • Every product code starts with P (single product) or K (kit)
  • The rest of the product code consists of four even digits

We need to define custom masking characters to implement the above rules. Check the following code.

const MaskedInput = (props) => {
  // Defining custom masking characters
  // P will match P or K
  // 0 (zero) will match even digits
  const formatChars = {
    'P': '[PK]',
    '0': '[02468]'
  };
  return (<InputMask 
    mask='P0000' 
    value={props.value} 
    onChange={props.onChange}
    formatChars={formatChars}
    placeholder='Eg: P2266'>
  </InputMask>)
};

Time input

Assume that you need to ask the user to enter a time by using the hh:mm format. The simpler implementation of the time input mask may use the 99:99 mask, but users can still enter some invalid time entries, such as 59:10, 08:65, etc.

An input mask typically refers to a string input with a specific format — not related to strict validation. However, we can apply conditional masking based on user input to add improvements to these scenarios.

For example, we can only accept the digits 0, 1, and 2 for the first mask character position. After that, we can change the second mask character’s logic based on the first digit of the user input.

Take a look at the following code that uses conditional masking.

function TimeInput(props) {
  let mask = '12:34';
  let formatChars = {
    '1': '[0-2]',
    '2': '[0-9]',
    '3': '[0-5]',
    '4': '[0-9]'
  };

  let beforeMaskedValueChange = (newState, oldState, userInput) => {
    let { value } = newState;

    // Conditional mask for the 2nd digit base on the first digit
    if(value.startsWith('2'))
      formatChars['2'] = '[0-3]'; // To block 24, 25, etc.
    else
      formatChars['2'] = '[0-9]'; // To allow 05, 12, etc.
    return {value, selection: newState.selection};
  }
return (
    <InputMask 
      mask={mask}
      value={props.value} 
      onChange={props.onChange}
      formatChars={formatChars}
      beforeMaskedValueChange={beforeMaskedValueChange}>
    </InputMask>
  );
}

The beforeMaskedValueChange event will be triggered before the masked input field gets updated with the most recent user input. This means we can use it to change the mask dynamically.

How to style input masks

The react-input-mask library renders masked input boxes using typical HTML inputs. Therefore, you can change styling by adding CSS classes as you wish. If you would like to use another component instead of HTML input, such as Material, implement your component as below.

import InputMask from 'react-input-mask';
import Input from '@material-ui/core/Input';

const MaskedInput = (props) => (
  <InputMask 
    mask='9999' 
    maskChar={null} 
    value={props.value} 
    onChange={props.onChange}
    placeholder='Enter your PIN'>
    {(inputProps) => <Input {...inputProps} />}
  </InputMask>
);

The above code snippet renders the Material input element instead of the native HTML input element as the masked PIN input field.

React input masking with Material UI components

Conclusion

The input masking concept is suitable for capturing user inputs with a specific, standard format, such as IP addresses, credit card numbers, product codes, and ID card numbers, among others.

The maintainer of the react-input-mask library is planning to release a new stable version (v3.0), and already there is a v3.0 alpha version with some enhancements and modifications to the API. The next stable release may contain their current development branch’s implementation. We used the current stable version (v2.0.4) in this tutorial because alpha-versioned dependencies are not recommended for any production system.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Shalitha Suranga Programmer | Author of Neutralino.js and Jerverless

One Reply to “Implementing react-input-mask for web apps”

Leave a Reply