View Password Button
A toggle button component that shows and hides password input content with eye icon indicators and full accessibility support.
Last updated on
A user-friendly password visibility toggle button that works seamlessly with password input fields. Features intuitive eye icons, smooth state management, and complete keyboard accessibility for enhanced user experience.
Installation
npx shadcn@latest add @grenish/view-passwordThis requires the @grenish registry in your components.json. See the installation guide for setup.
Manual Dependencies
If you prefer manual installation, add the base components:
npx shadcn@latest add button input input-groupUsage
import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
import ViewPasswordButton from "@/components/tools/view-password"
export default function PasswordField() {
return (
<InputGroup>
<InputGroupInput
id="password-field"
type="password"
placeholder="Enter password"
/>
<ViewPasswordButton inputId="password-field" />
</InputGroup>
)
}"use client";
import { useState } from "react";
import { EyeClosedIcon, EyeIcon } from "@phosphor-icons/react/dist/ssr";
import { InputGroupAddon, InputGroupButton } from "../ui/input-group";
interface ViewPasswordButtonProps {
inputId: string;
}
export default function ViewPasswordButton({
inputId,
}: ViewPasswordButtonProps) {
const [isVisible, setIsVisible] = useState(false);
const handleToggle = () => {
const input = document.getElementById(inputId) as HTMLInputElement;
if (input) {
input.type = !isVisible ? "text" : "password";
setIsVisible(!isVisible);
}
};
return (
<InputGroupAddon align={"inline-end"}>
<InputGroupButton
onClick={handleToggle}
type="button"
aria-label="Toggle password visibility"
>
{isVisible ? (
<EyeIcon weight="bold" />
) : (
<EyeClosedIcon weight="bold" />
)}
</InputGroupButton>
</InputGroupAddon>
);
}Features
- Eye Icon Indicators: Shows eye when visible, eye-closed when hidden using Phosphor Icons
- Smart Toggle: Switches input type between "password" and "text" seamlessly
- State Management: Internal state tracking for visibility state
- InputGroup Integration: Built to work perfectly with the InputGroup component suite
- Accessible: Includes aria-label for screen reader support
- DOM Manipulation: Direct access to input via ID for type switching
- Bold Icons: Eye icons use bold weight for clarity and visibility
- Inline End Position: Positioned at the right side of input field
- Button Type Safe: Uses type="button" to prevent form submission
- Keyboard Friendly: Full keyboard navigation support
Props
Prop
Type
Examples
Basic Password Field
Simple password input with toggle visibility.
import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
import ViewPasswordButton from "@/components/tools/view-password"
export function BasicPasswordField() {
return (
<InputGroup>
<InputGroupInput
id="password"
type="password"
placeholder="Enter your password"
/>
<ViewPasswordButton inputId="password" />
</InputGroup>
)
}Login Form
Complete login form with email and password fields.
Sign In
import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
import ViewPasswordButton from "@/components/tools/view-password"
import { useState } from "react"
export function LoginForm() {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// Handle login
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<InputGroup>
<InputGroupInput
id="login-email"
type="email"
placeholder="your@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</InputGroup>
<InputGroup>
<InputGroupInput
id="login-password"
type="password"
placeholder="Enter password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<ViewPasswordButton inputId="login-password" />
</InputGroup>
<Button>Sign in</Button>
</form>
)
}