Password and Confirm Password matching functionality is one of the very common requirement in most of the applications containing registration forms. We are going to implement the same using React JS in multiple ways without depending on any external library.

Output will be something like this:

When passwords are not matching

When passwords are matching:

We have used bootstrap CSS for styling and you are free to use any CSS of your choice.

How we are going to implement:

We are going to implement password and confirm password matching functionality in React JS application with Function Components in two different ways without using any third party library

  • By using Controlled Inputs
  • By using useRef hook

Matching Password and Confirm Password in React JS using Controlled Input Elements

First we are going to import useState and useEffect along with React which will be used later like this

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

Now, we are going to create few state variables

    const [password, setPassword] = useState('');
    const [cPassword, setCPassword] = useState('');
    const [showErrorMessage, setShowErrorMessage] = useState(false);
    const [cPasswordClass, setCPasswordClass] = useState('form-control');
    const [isCPasswordDirty, setIsCPasswordDirty] = useState(false);

The password and cPassword state variables will be used to store the values of password and confirm password input elements. showErrorMessage will be used as a flag to display the error message or not. cPasswordClass will be used to change the CSS classes applied on the confirm password element. And finally, isCPasswordDirty is used to display the error message or change the CSS class names only when the user changes the value of confirm password.

Now, we will add the HTML:

return (
        <div className='container' >
            <form>
                <div className="mb-3">
                    <label htmlFor="password" className="form-label">Password</label>
                    <input type="password" className="form-control" id="password" value={password}
                        onChange={(e) => { setPassword(e.target.value) }} />
                </div>
                <div className="mb-3">
                    <label htmlFor="confirmPassword" className="form-label">Confirm Password</label>
                    <input type="password" className={cPasswordClass} id="confirmPassword" value={cPassword}
                        onChange={handleCPassword} />
                </div>
                {showErrorMessage && isCPasswordDirty ? <div> Passwords did not match </div> : ''}

                <button type="submit" className="btn btn-primary">Submit</button>
            </form>
        </div>
    )

In the above code, we added password state variable to the first input element and when the value changes we are changing its value by passing the event target value to setPassword. We used showErrorMessage and isCPasswordDirty to display the error message conditionally.

Instead of assigning static CSS classes, we have assigned cPasswordClass state variable value to confirm password class name.

Now coming to the important part of the task, that is to compare passwords, we want to do it when the value of confirm password changes. Here is what we are doing inside the event handler function

const handleCPassword = (e) => {
        setCPassword(e.target.value);
        setIsCPasswordDirty(true);
    }

You can see in the code above that, we are only assigning the value of confirm password to cPassword state variable by using its setter function setCPassword and also change the value of isCPasswordDirty to true.

We are not comparing the passwords here. Why ? Suppose if we compare the values after setCPassword, since the setter functions are asynchronous in React JS, we will not be having the value of confirm password immediately at that moment. So, we will create a useEffect function which gets executed whenever the value of cPassword changes. In this way, it is guaranteed that the updated value will be available when we are doing the comparison.

useEffect(() => {
        if (isCPasswordDirty) {
            if (password === cPassword) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }
    }, [cPassword])

Another thing to note in the above code is that, we are comparing and setting the CSS classes only when the isCPasswordDirty is true. This prevents this code getting executed in the initial run. If we do not do it, since the values of password and confirm password will be empty in the initial run which will be equal and the new CSS classes will gets applied immediately (if you want, you can achieve this in other ways also such as, comparing only when the values of password and confirm password are not empty) .

Full Code:

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

function PWCPW() {

    const [password, setPassword] = useState('');
    const [cPassword, setCPassword] = useState('');
    const [showErrorMessage, setShowErrorMessage] = useState(false);
    const [cPasswordClass, setCPasswordClass] = useState('form-control');
    const [isCPasswordDirty, setIsCPasswordDirty] = useState(false);

    useEffect(() => {
        if (isCPasswordDirty) {
            if (password === cPassword) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }
    }, [cPassword])

    const handleCPassword = (e) => {
        setCPassword(e.target.value);
        setIsCPasswordDirty(true);
    }

    return (
        <div className='container' >
            <form>
                <div className="mb-3">
                    <label htmlFor="password" className="form-label">Password</label>
                    <input type="password" className="form-control" id="password" value={password}
                        onChange={(e) => { setPassword(e.target.value) }} />
                </div>
                <div className="mb-3">
                    <label htmlFor="confirmPassword" className="form-label">Confirm Password</label>
                    <input type="password" className={cPasswordClass} id="confirmPassword" value={cPassword}
                        onChange={handleCPassword} />
                </div>
                {showErrorMessage && isCPasswordDirty ? <div> Passwords did not match </div> : ''}

                <button type="submit" className="btn btn-primary">Submit</button>
            </form>
        </div>
    )
}

export default PWCPW

Matching Password & Confirm Password in React JS using useRefs

Now, we will see, how to implement the same functionality using useRefs.

First import useState, useRef, useEffect with React

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

Lets first create some state variables and references for input elements

    const password = useRef();
    const cPassword = useRef();
    const [showErrorMessage, setShowErrorMessage] = useState(false);
    const [cPasswordClass, setCPasswordClass] = useState('form-control');
    const [isCPasswordDirty, setIsCPasswordDirty] = useState(false);

here again we have three state variables which doing the exactly the same purpose as they were in the earlier example. We then have two reference variables to hold the values of password and confirm password.

HTML:

return (
        <div className='container' >
            <form>
                <div className="mb-3">
                    <label htmlFor="password" className="form-label">Password</label>
                    <input type="password" className="form-control" id="password" ref={password} />
                </div>
                <div className="mb-3">
                    <label htmlFor="confirmPassword" className="form-label">Confirm Password</label>
                    <input type="password" className={cPasswordClass} id="confirmPassword" ref={cPassword}
                        onChange={checkPasswords} />
                </div>
                {showErrorMessage && isCPasswordDirty ? <div> Passwords did not match </div> : ''}

                <button type="submit" className="btn btn-primary">Submit</button>
            </form>
        </div>
    )

The above code is almost similar to the code from earlier example. The changes here are, we have added references to input elements.

We are running the checkPasswords function when the user changes the value of confirm password input element.

const checkPasswords = (e) => {
        setIsCPasswordDirty(true);
        if (isCPasswordDirty) {
            if (password.current.value === cPassword.current.value) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }

    }

useEffect(() => {
        if (isCPasswordDirty) {
            if (password.current.value === cPassword.current.value) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }
    }, [isCPasswordDirty])

When the user changes the value of confirm password the very first time, the comparison code in the checkPasswords function do not get executed. The reason is same as we have seen in the first example. That is, the value of isCPasswordDirty will be false in the if statement inside the checkPasswords function for the very first time as setIsCPasswordDirty will get executed asynchronously. So we have used useEffect hook to handle this situation.

Full Code:

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

function PWCPW() {

    const password = useRef();
    const cPassword = useRef();
    const [showErrorMessage, setShowErrorMessage] = useState(false);
    const [cPasswordClass, setCPasswordClass] = useState('form-control');
    const [isCPasswordDirty, setIsCPasswordDirty] = useState(false);

    useEffect(() => {
        if (isCPasswordDirty) {
            if (password.current.value === cPassword.current.value) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }
    }, [isCPasswordDirty])

    const checkPasswords = (e) => {
        setIsCPasswordDirty(true);
        if (isCPasswordDirty) {
            if (password.current.value === cPassword.current.value) {
                setShowErrorMessage(false);
                setCPasswordClass('form-control is-valid')
            } else {
                setShowErrorMessage(true)
                setCPasswordClass('form-control is-invalid')
            }
        }

    }

    return (
        <div className='container' >
            <form>
                <div className="mb-3">
                    <label htmlFor="password" className="form-label">Password</label>
                    <input type="password" className="form-control" id="password" ref={password} />
                </div>
                <div className="mb-3">
                    <label htmlFor="confirmPassword" className="form-label">Confirm Password</label>
                    <input type="password" className={cPasswordClass} id="confirmPassword" ref={cPassword}
                        onChange={checkPasswords} />
                </div>
                {showErrorMessage && isCPasswordDirty ? <div> Passwords did not match </div> : ''}

                <button type="submit" className="btn btn-primary">Submit</button>
            </form>
        </div>
    )
}

export default PWCPW

Apart from the solutions provided above, you may have to consider few other situations in real time applications, such as, after entering confirm password, a user may go back to password and change it etc.,

If you want to implement the same using only JavaScript, check this post Matching Password & Confirm Password with JavaScript