Tools

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-password

This 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-group

Usage

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>
  )
}

On this page