This is a simple blog on how you can add a simple eye icon next to the password field of your login/sign up form.
The end result would look something like:
What we want:
- An eye off icon next to the password field only after the password field has some non-empty value inside
- When clicked on eye off, it should reveal password and the icon should change to eye.
All you need for this is:
- 2 React Icons (RiEyeFill and RiEyeOffFill) (you can search for other icons on [https://react-icons.github.io/react-icons])
- Knowledge of the useState hook in React
So let me take you with what I'm working. I have a form component in Nextjs using the React-Hook-Form and other components by ShadcnUI.
Let's say we're working on the login form (you can follow the same steps for the signup as well)
In the login form, I have 2 form fields.
An email field and a password field.
Step 1: Import the React icons.
import { RiEyeFill, RiEyeOffFill } from "react-icons/ri";
Step 2: Go all the way down to your password field input.
For me, it looks like:
Try rendering an icon here. In order to render it next to the password, wrap the Input in a div and add a button in the same row using flex.
<FormControl>
<div className="flex flex-row">
<Input
placeholder="******"
type="password"
{...field}
disabled={isPending}
/>
<button className="ml-4 text-gray-700">
<RiEyeOffFill />
</button>
</div>
</FormControl>
But what I want is that the icon should be displayed only when there is something inside the password field.
For that, create a state at the top:
const [isPasswordTyping, setIsPasswordTyping] = useState(false);
Inside the Input tag, whenever there is a change in the password field, create an onChange event that sets this isPasswordTyping to true. Or rather, length > 0.
onChange={(e) => {
field.onChange(e);
setIsPasswordTyping(e.target.value.length > 0);
}}
This field
is something that Shadcn's React-Hook-Form provides.
Finally render the button only if isPasswordTyping is true.
So now, you will only see the icon rendered if the password has a non empty field inside.
<FormControl>
<div className="flex flex-row">
<Input
placeholder="******"
type="password"
{...field}
onChange={(e) => {
field.onChange(e);
setIsPasswordTyping(e.target.value.length > 0);
}}
disabled={isPending}
/>
{isPasswordTyping && (
<button className="ml-4 text-gray-700">
<RiEyeOffFill />
</button>
)}
</div>
</FormControl>
Step 3: Toggle Visibility and change icon
We need to render the password as text if a variable "showPassword" is true, and the password as password (******) if "showPassword" is false.
For that create a state,
const [showPassword, setShowPassword] = useState(false);
and in the Input, add the line: type={showPassword ? "text" : "password"}
<Input
placeholder="******"
type={showPassword ? "text" : "password"}
{...field}
onChange={(e) => {
field.onChange(e);
setIsPasswordTyping(e.target.value.length > 0);
}}
disabled={isPending}
/>
We need to render the icon. if showPassword is true, then we need to render the EyeFill icon, else the EyeOffFill.
<button className="ml-4 text-gray-700">
{showPassword ? <RiEyeFill /> : <RiEyeOffFill />}
</button>
Finally, we need to add an onClick to this button and toggle the visibility.
const togglePasswordVisibility = () => {
setShowPassword((prev) => !prev);
};
<button type="button" onClick={togglePasswordVisibility} className="ml-4 text-gray-700">
{showPassword ? <RiEyeFill /> : <RiEyeOffFill />}
</button>
And we're done. Here's a live demo:
Thanks for reading. Let me know if you have any questions!
Happy coding.
Top comments (0)