Password Input
A specialized input component for passwords with built-in visibility toggling, customizable icons, and full accessibility support.
Installation
Run the following command to add the password-input component to your project using the Flow UI CLI:
npx theflowui add password-inputInstall Dependencies
Ensure you have lucide-react installed for the default icons.
npm install lucide-reactCreate Password Input Component
Create a new file password-input.tsx in your components folder (e.g., components/ui/password-input.tsx) and copy the code below.
"use client";
import { cn } from "@/lib/utils";
import { Eye, EyeOff } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import { ComponentPropsWithoutRef, forwardRef, useState } from "react";
type PasswordInputProps = {
className?: string;
containerClassName?: string;
visibleIcon?: LucideIcon;
hiddenIcon?: LucideIcon;
} & ComponentPropsWithoutRef<"input">;
const PasswordInput = forwardRef<
HTMLInputElement,
PasswordInputProps
>(
({
className,
containerClassName,
disabled,
visibleIcon = Eye,
hiddenIcon = EyeOff,
...props
},
ref
) => {
// State to handle password visibility
const [visible, setVisible] = useState<boolean>(false);
// Icon selection based on the visibility state
const Icon = visible ? visibleIcon : hiddenIcon;
// Function to handle the visibility toggle
const handleVisibility = () => {
if (!disabled) {
setVisible((prev) => !prev);
}
}
return (
<div
className={cn(
"relative flex items-center border border-input bg-background rounded-md ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
containerClassName
)}
>
<input
ref={ref}
type={visible ? "text" : "password"}
disabled={disabled}
className={cn(
"flex rounded-md px-3 py-1.5 pe-10 disabled:cursor-not-allowed disabled:opacity-50 outline-none w-full",
className
)}
{...props}
/>
<button
type="button"
onClick={handleVisibility}
disabled={disabled}
aria-label={visible ? "Hide password" : "Show password"}
className={cn(
"absolute right-0 me-3 inline-flex justify-center items-center text-muted-foreground hover:text-foreground focus:outline-none disabled:opacity-50"
)}
>
<Icon
className="size-5"
/>
</button>
</div>
)
}
);
PasswordInput.displayName = "PasswordInput";
export { PasswordInput };Usage
Custom Icons
You can customize the icons used for toggling visibility by passing components to visibleIcon and hiddenIcon props.
import { PasswordInput } from "@/components/ui/password-input";
import { Lock, Unlock } from "lucide-react";
export function CustomIconsExample() {
return (
<PasswordInput
visibleIcon={Unlock}
hiddenIcon={Lock}
placeholder="Custom lock icons..."
/>
);
}Custom Styling
You can customize the outer container, i.e. give border and outline on focus using focus-within tailwind class. You can also
style the Icon, so show your creativity.
import { PasswordInput } from "@/components/ui/password-input";
import { Lock, Unlock } from "lucide-react";
export const CustomizedExample = () => {
return (
<PasswordInput
containerClassName="focus-within:ring-2 focus-within:ring-accent"
placeholder="password"
/>
);
}Disabled State
The component handles the disabled state by preventing interaction and applying appropriate styles.
import { PasswordInput } from "@/components/ui/password-input";
<PasswordInput disabled value="secretpassword" />Props
The PasswordInput component accepts all native <input> HTML attributes, plus the following:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the input element. |
containerClassName | string | - | Additional CSS classes for the wrapper container. |
iconClassName | string | - | Additional CSS classes for the icon. |
visibleIcon | LucideIcon | Eye | Icon to show when the password is visible. |
hiddenIcon | LucideIcon | EyeOff | Icon to show when the password is hidden. |
Accessibility
The component automatically handles ARIA labels for the visibility toggle button and uses type="password" or type="text" appropriately to ensure password managers and screen readers behave correctly.