Create Login Form with show/hide password field in React.
Tags: react, javascript, tailwindcss, webdev
Published: 2021-11-18 18:35:14

I was creating authentication functionality, login/signup form for one of my projects. I wanted to implement a very simple functionality of showing/hiding the password field on clicking an eye button. But believe me, it gave a bit of hard time. I searched on the internet and I did find some great resources. There was an article in GeeksforGeeks which did help a lot. But here I have summed up the entire login front-end functionality i.e getting user data, storing it in state and show/hide password field. Also I noticed during implementation that on clicking the eye icon to show the password, the cursor moves to the beginning of the input field which seems odd. In the end I did found a solution to that issue. So, you should read the entire post if you are facing the same issue.

##Basic setup
1.React 
2.Tailwind
3.Heroicons

##Defining states
Let's define two states, one for email and other for password. I think we have to define as many states as input fields present in our form.

```javascript
const [emailValue, setEmailValue] = useState({
    email: "",
  });
const [passValue, setPassValue] = useState({
    password: "",
    showPassword: false,
  });

```
As you can see passValue has additional showPassword field. This state value will be used for show/hide password funcitonality.

##Rendering the component
The jsx code is pretty straight forward. I have styled the form using tailwind css b.t.w tailwind is awesome. Also I have defined few functions for onChange and onClick actions.

```javascript
<div className="login_page">
      <main className="login_main max-w-lg mx-auto ">
        <div className="login_form pt-16">
          <h2 className="text-3xl">Sign in</h2>
          <form action="">
            <div className="email pt-8 block ">
              <label htmlFor="" className="label ">
                Email Address
              </label>
              <input
                className="input block border border-gray-300 focus:border-pitch-black  py-3 px-3 w-full focus:outline-none "
                type="text"
                name="email"
                value={emailValue.email}
                onChange={handleEmailValue}
              />
            </div>
            <div className="password_2 block pt-6 relative">
              <label>Password</label>
              <div className="eye_div">
                <input
                  className="input block border border-gray-300 focus:border-pitch-black  py-3 px-3 w-full focus:outline-none "
                  type="password"
                  onChange={handlePasswordChange("password")}
                  value={passValue.password}
                />
                <div
                  className="icon_button absolute right-4 top-14"
                  onClick={handleClickShowPassword}
                >
                  {passValue.showPassword ? (
                    <EyeIcon className="h-6 font-extralight" />
                  ) : (
                    <EyeOffIcon className="h-6 font-extralight" />
                  )}
                </div>
              </div>
              <p className="pt-4">Forgot your password?</p>
            </div>
            <button
              className="mt-9 p-3 bg-pitch-black hover:bg-opacity-80 text-white w-full text-sm"
            >
              Sign In
            </button>
            <div className="w-full h-px bg-gray-300 mt-12"></div>
            <h3 className="text-center pt-7 text-lg">Don't have an account?</h3>
            <button className="mt-8 p-3 mb-16 bg-white hover:bg-opacity-80 border border-pitch-black w-full text-sm">
              Create Account
            </button>
          </form>
        </div>
      </main>
    </div>
```
I have used HeroIcons (EyeOff and EyenOn) which shows depending upon the showPassword value.
As of now the component looks like this without any functionality.
<img width="100%" style="width:100%" src="https://media.giphy.com/media/5RYrDKAAxPm3KS43uP/giphy.gif">

##Functions for handling states
I have defined two functions for each input field that stores/change the state when user input value to each field.
```javascript
const handleEmailValue = (e) => {
    const { name, value } = e.target;
    setEmailValue({
      ...emailValue,
      [name]: value,
    });
  };
 const handlePasswordChange = (prop) => (event) => {
    setPassValue({ ...passValue, [prop]: event.target.value });
  };
```
When the user clicks the Eye icon we change the value of showPassword to either true or false. Depending on the value of showPassword we also change the type of input field to either text or password. This gives the show/hide password functionality.
```javascript
const handleClickShowPassword = () => 
    setPassValue({ ...passValue, showPassword: !passValue.showPassword });
  };
```
Now our component looks the same but with a bit of funcitonality. Cool...
<img width="100%" style="width:100%" src="https://media.giphy.com/media/T4toraiq8HgoPlf4Xt/giphy.gif">

##Issues

If you look closely in the above gif you can see that when we toggle the EyeButton the cursor position changes. This is a small issue but it was really bugging me. So as everyone else I searched on internet to find any solution but couldn't found any . But what I found was a simple trick to disappear the cursor if input type is password. The way to make cursor disappear is to make it's caretColor property transparent. We need to refactor our jsx and handleClickShowPassword funciton .
```javascript 
//Input field jsx
<input
   className="input block border border-gray-300 focus:border-pitch-black  py-3 px-3 w-full focus:outline-none "
   onClick={() => setCaretColor("black")}
   style={{ caretColor: caretColor }}
   type={values.showPassword ? "text" : "password"}
   onChange={handlePasswordChange("password")}
   value={values.password}
 />
//handleClickShowPassword 
 const handleClickShowPassword = () => {
    setCaretColor("transparent");
    setValues({ ...values, showPassword: !values.showPassword });
  };
```
##Final Result
<img width="100%" style="width:100%" src="https://media.giphy.com/media/FuYcHH6Zq3K7n9F1H6/giphy.gif">

There you have it a simple login form. You have the show/hide functionality without any issues. You have the user input data that you can send to the backend for authentication.
If you have any good suggestions/refactors do comment below. Also if I can help in any projects I would love to. I am open to new opportunities.