Something new is coming.Join the waitlist

Password Input

PreviousNext

Password field with show/hide toggle, zxcvbn-ts strength meter, Caps Lock indicator, and paste disabled by default.

Installation

npx shadcn@latest add https://ui.srb.codes/r/password-input.json

Usage

"use client";
 
import * as React from "react";
 
import { PasswordInput } from "@/components/password-input";
 
export function SignupField() {
  const [value, setValue] = React.useState("");
 
  return (
    <PasswordInput
      name="password"
      autoComplete="new-password"
      placeholder="At least 12 characters"
      value={value}
      onChange={(event) => setValue(event.target.value)}
    />
  );
}

Patterns

Confirm-password field

The classic "type it twice" flow. Skip the strength meter on the confirm field — it's already shown on the primary field — and flip aria-invalid when the two values diverge so the input picks up the registry's destructive ring.

<PasswordInput
  name="passwordConfirm"
  autoComplete="new-password"
  showStrengthMeter={false}
  aria-invalid={confirm !== password}
/>

Detecting paste attempts

Paste is always blocked, but the component still tells you when someone tried — useful for soft warnings, telemetry, or fraud signals.

<PasswordInput
  onPasswordPaste={(_, pasted) => {
    track("password_paste_blocked", { length: pasted.length });
  }}
/>

Props

PropTypeDefaultDescription
valuestringControlled value. Omit for uncontrolled mode (use defaultValue).
defaultValuestring""Initial value when uncontrolled.
onChange(event) => voidStandard change handler. Forwarded to the underlying <input>.
showStrengthMeterbooleantrueRender the four-segment zxcvbn strength meter and contextual messages below the input.
showTogglebooleantrueRender the show/hide eye button. The button is tabIndex={-1} so keyboard users tab past it to the next field.
showCapsLockHintbooleantrueShow the small "Caps" pill inside the input while focused with CapsLock on.
onPasswordPaste(event, pastedText) => voidFires for every paste attempt. The event has already been preventDefault'd — paste is always blocked; this hook is for telemetry.
autoCompletestring"current-password"Defaults to the sign-in autocomplete token. Pass "new-password" on signup and confirm flows.

All other native <input> attributes (name, id, placeholder, disabled, required, aria-invalid, etc.) are forwarded. The native onPaste is omitted on purpose — use onPasswordPaste so paste behavior can't be silently re-enabled by a downstream consumer.

Why paste is blocked

Pasting from a clipboard hides what the user actually committed: typos, leading spaces from copy-from-document, or a value pasted from the wrong field. Forcing the user to type the password also gives the strength meter and Caps Lock indicator something to react to. If your flow needs paste — for example a randomly generated value piped through a password manager — pair <PasswordInput> with a regular <Input type="password" /> for that one case rather than re-enabling paste here.

Strength meter

The meter is driven by @zxcvbn-ts/core — the maintained TypeScript port of Dropbox's zxcvbn. The four segments fill left-to-right based on the score (0–4):

ScoreLabelColor
0Very weakdestructive
1Weakdestructive
2Fairamber-500
3Goodemerald-500
4Strongemerald-600

The shared language-common dictionary is loaded lazily on first use and cached per page. It's about 100 KB gzipped — not nothing, but only paid once and only on pages that actually render a PasswordInput. If you need locale-specific dictionaries (German, French, etc.) install the matching @zxcvbn-ts/language-* packages and call zxcvbnOptions.setOptions yourself before this component mounts.

Accessibility

  • The strength meter is announced via role="progressbar" with aria-valuemin, aria-valuemax, aria-valuenow, and a human-readable aria-valuetext ("Weak", "Strong", …).
  • Strength messages render inside aria-live="polite" so they're read by screen readers without interrupting typing.
  • The toggle button is labelled "Show password" / "Hide password" and exposes aria-pressed so assistive tech announces the current state.
  • The toggle button is removed from the tab order (tabIndex={-1}) so keyboard users move directly from the password field to the submit button.
  • Caps Lock hint is aria-hidden because the visual styling is for sighted users; password managers and screen readers handle this concern themselves.