I'm building a registration form and I'm having trouble positioning the eye icon. Initially, the icon is positioned correctly, but when an error message is displayed, it gets misaligned.
Here are some screenshots showing the issue, along with the code I'm using.
Additionally, I can't figure out how to make the error message icon larger. For longer error messages, the icon becomes too small.
This is my code:
<div className="mt-6">
<label htmlFor="password" className="block text-sm font-normal text-gray-700">
Contraseña
</label>
<div className="mt-1 relative">
<input
id="password"
name="password"
type={showPassword ? 'text' : 'password'}
autoComplete="current-password"
placeholder="Contraseña"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
onBlur={() => handleBlur('password')}
className="block w-full appearance-none placeholder:text-xs rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-950 focus:outline-none sm:text-sm"
/>
<span
onClick={togglePasswordVisibility}
className="absolute inset-y-0 right-0 pr-3 flex items-center cursor-pointer justify-center"
>
{showPassword ? <VscEyeClosed /> : <VscEye />}
</span>
{passwordError && (
<p className="mt-2 text-xs text-red-600 flex items-center">
<TiWarning className="mr-1" /> {passwordError}
</p>
)}
</div>
</div>
I'm using Tailwind CSS, and to be honest, I don't have much experience with frontend development. It feels like a nightmare for a backend developer! Could someone help me fix these issues?
For positioning the eye icon:
I replaced inset-y-0
with top-3
to ensure consistent alignment, as inset-y-0
adjusts dynamically based on the height of the input. Using top-3
fixes the position relative to the top of the input field.
<span
onClick={togglePasswordVisibility}
className="absolute top-3 right-0 pr-3 flex items-center cursor-pointer justify-center"
>
{showPassword ? <VscEyeClosed /> : <VscEye />}
</span>
For the warning icon size issue:
I added flex-shrink-0
to prevent the icon from shrinking when the error message wraps to multiple lines. Additionally, I set explicit height (h-4
) and width (w-4
) to maintain consistent size.
<TiWarning className="mr-1 flex-shrink-0 h-4 w-4 text-lg" />
Here’s the full updated code:
<div className="mt-6">
<label
htmlFor="password"
className="block text-sm font-normal text-gray-700"
>
Contraseña
</label>
<div className="mt-1 relative">
<input
id="password"
name="password"
type={showPassword ? "text" : "password"}
autoComplete="current-password"
placeholder="Contraseña"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
onBlur={() => handleBlur("password")}
className="block w-full appearance-none placeholder:text-xs rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-950 focus:outline-none sm:text-sm"
/>
<span
onClick={togglePasswordVisibility}
className="absolute top-3 right-0 pr-3 flex items-center cursor-pointer justify-center"
>
{showPassword ? <VscEyeClosed /> : <VscEye />}
</span>
{passwordError && (
<p className="mt-2 text-xs text-red-600 flex items-center">
<TiWarning className="mr-1 flex-shrink-0 h-4 w-4 text-lg" />
{passwordError}
</p>
)}
</div>
</div>
These changes ensure the components remain properly aligned and visually consistent regardless of input height or error message length.