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.
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.
<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.
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.
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.
const handleClickShowPassword = () =>
setPassValue({ ...passValue, showPassword: !passValue.showPassword });
};
Now our component looks the same but with a bit of funcitonality. Cool...
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 .
//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
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.
Top comments (1)
doesn't work for me i think you forgot to share password_2 & eye_div classes