VibeUI
ComponentsDocs
VibeUI

Components with taste, that you own. Copy the source, retint the tokens, keep every line.

Library

  • All components
  • Signature pieces
  • Text effects
  • Footers

Docs

  • Introduction
  • Installation
  • Theming
  • CLI

Project

  • GitHub
  • Agents and MCP
  • Issues
  • MIT license
© 2026 VibeUI · MIT licensed
  1. Components
  2. Forms
  3. Password Field

Password Field

Password input with a show/hide toggle.

FormsClient component

Install

bash
npx @agents-npm-packages/vibeui add password-field --dir ./src/components/ui

Import

tsx
import { PasswordField } from "@/components/ui/password-field"

API

Generated from the component's TypeScript types, so it always matches the source. * marks a required prop.

<PasswordField>

also accepts every InputHTMLAttributes<HTMLInputElement> attribute

No props of its own: it forwards native attributes to the element.

Source

src/components/ui/password-field.tsx
"use client";

import * as React from "react";
import { Eye, EyeSlash } from "@phosphor-icons/react";
import { cn } from "@/lib/utils";

/** Password input with a show/hide toggle. */
export function PasswordField({
  className,
  ...props
}: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type">) {
  const [visible, setVisible] = React.useState(false);

  return (
    <div className={cn("relative", className)}>
      <input
        type={visible ? "text" : "password"}
        className="h-10 w-full rounded-sm border border-line-strong bg-surface pl-3 pr-10 text-sm text-ink shadow-quiet placeholder:text-faint transition-[border-color,box-shadow] duration-150 hover:border-faint focus-visible:border-accent focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring disabled:opacity-50"
        {...props}
      />
      <button
        type="button"
        aria-label={visible ? "Hide password" : "Show password"}
        aria-pressed={visible}
        onClick={() => setVisible((v) => !v)}
        className="absolute right-1.5 top-1/2 flex size-7 -translate-y-1/2 items-center justify-center rounded-[6px] text-faint transition-colors hover:bg-surface-muted hover:text-ink"
      >
        {visible ? (
          <EyeSlash key="hide" size={16} weight="bold" className="animate-pop-in" />
        ) : (
          <Eye key="show" size={16} weight="bold" className="animate-pop-in" />
        )}
      </button>
    </div>
  );
}

Exports PasswordField. Peer dependencies: clsx, tailwind-merge, @phosphor-icons/react.

PreviousOtp FieldNextRadio