DEV Community

Cover image for Input Mask in React without libraries
Juan Manuel Crego Risso
Juan Manuel Crego Risso

Posted on

Input Mask in React without libraries

How to create a simple input mask only with React:

There are many libraries to do this, but it is always good to know how to do things that work in any type of web development. In this case we will create an entry for credit cards.

Step 1:

In a functional component we import

import React, { useState, useEffect, useRef } from 'react';
Enter fullscreen mode Exit fullscreen mode

Now, we can created the component, in this case, the name is InputMask

const InputMask = () => {

}

export default InputMask;

Enter fullscreen mode Exit fullscreen mode

Step 2:

We create first a new state, called card, and setCard is the function to modify that state, later we create a const called inputCard for the useRef hook.

import React, { useState, useEffect, useRef } from "react";

const InputMask = () => {
  const [card, setCard] = useState();
  const inputCard = useRef()
}

export default InputMask;
Enter fullscreen mode Exit fullscreen mode

Now, we return an input with a ref property binding the InputCard const

import React, { useState, useEffect, useRef } from 'react';

const InputMask = () => {
  const [card, setCard] = useState();
  const inputCard = useRef();

  return (
    <>
      <input type="text" ref={inputCard} />
    </>
  );
};

export default InputMask;
Enter fullscreen mode Exit fullscreen mode

If you do not know the hook useRef I share the official React documentation for useRef in this link

Step 3:

Now, we can target the events of the input, useRef works like a eventListener in JavaScript! For that, we create a function called handleChange and pass this function to the input in a onChange event

import React, { useState, useEffect, useRef } from 'react';

const InputMask = () => {
  const [card, setCard] = useState();
  const inputCard = useRef();

  const handleChange = () => {

  };

  return (
    <>
      <input type="text" ref={inputCard} onChange={handleChange} />
    </>
  );
};

export default InputMask;
Enter fullscreen mode Exit fullscreen mode

Step 4:

In handleChange we use regex (Regular expressions) in a first step we use replace to replace all the expressions that not numbers with a blank space, later we use match for grouping the digits of the credit card in four groups of four digits each one

import React, { useState, useEffect, useRef } from 'react';

const InputMask = () => {
  const [card, setCard] = useState();
  const inputCard = useRef();

  const handleChange = () => {
    const cardValue = inputCard.current.value
      .replace(/\D/g, '')
      .match(/(\d{1,4})(\d{0,4})(\d{0,4})(\d{0,4})/);
    inputCard.current.value = !cardValue[2]
      ? cardValue[1]
      : `${cardValue[1]}-${cardValue[2]}
      ${(`${cardValue[3] ? `-${cardValue[3]}` : ''}`)}
      ${(`${cardValue[4] ? `-${cardValue[4]}` : ''}`)}`;
  };

  return (
    <>
      <input type="text" ref={inputCard} onChange={handleChange} />
    </>
  );
};

export default InputMask;
Enter fullscreen mode Exit fullscreen mode

Look at this, after match, we use aternary operator to set the value forinputCard in a first step, we set the condition of the second group to false, because group one will always exist, in a second step , we write many conditions, at the beginning group one, then the second group will continue, then if group three exists it will be after a -, the same is for group four...

Step 5:

Finally, we use the useEffect hook to manage the component lifecycle, inside useEffect, we set the callback for handleChange, and we specify the render when the card state changes, for this, we use setCard to save the input value on card state

import React, { useState, useEffect, useRef } from 'react';

const InputMask = () => {
  const [card, setCard] = useState();
  const inputCard = useRef();

  const handleChange = () => {
    const cardValue = inputCard.current.value
      .replace(/\D/g, '')
      .match(/(\d{0,4})(\d{0,4})(\d{0,4})(\d{0,4})/);
    inputCard.current.value = !cardValue[2]
      ? cardValue[1]
      : `${cardValue[1]}-${cardValue[2]}${`${
          cardValue[3] ? `-${cardValue[3]}` : ''
        }`}${`${cardValue[4] ? `-${cardValue[4]}` : ''}`}`;
    const numbers = inputCard.current.value.replace(/(\D)/g, '');
    setCard(numbers);
  };

  useEffect(() => {
    handleChange();
  }, [card]);

  return (
    <>
      <input type="text" ref={inputCard} onChange={handleChange} />
    </>
  );
};

export default InputMask;
Enter fullscreen mode Exit fullscreen mode

This code works on phone inputs! in that case we must use (xxx) in the beginning of the input.

Demo

Hope you like this post!

Top comments (7)

Collapse
 
jaisaro14 profile image
Jai Saravanan

Your demo is not opening.

Collapse
 
anisamirouche profile image
Anis Amirouche

Thanks for the artcile it's very useful , can you explain more about phone inputs ? where to add (XXX) ?

Collapse
 
kiranmantha profile image
Kiran Mantha

change the regex as per your need and it should work..

Collapse
 
iqrivas profile image
Denisse Rivas

🤯 Thanks for sharing! I like to always first try to look for how to do it without libraries. I like how you built the structure step by step, it was easy to understand.

Collapse
 
aman009006 profile image
Aman Mamashov

its code not valide, because useEffect(()=> { setState() },[ state ]). Your useEffect will work infinity

Collapse
 
kiranmantha profile image
Kiran Mantha

right. we don't need that useEffect. you can print the value of card and verify

Collapse
 
jonathanafranio profile image
Jonathan Afranio

Thanks bro! (y)