Password Input React component for Tailwind CSS v4
v1.0.0Added in 1.0.0
A password field with a caret-safe reveal toggle, a Caps Lock warning and, for sign-up, a strength meter, rules checklist and generator.
Tap the eye and the dots turn into text with the icon turning a quarter over; the caret and any selection stay exactly where they were, and the button stays in the Tab order. With Caps Lock on, a small amber warning slides in under the box and leaves when you release it or leave the field. With strength on, four bars fill left to right as you type, red, then amber, then green, with the verdict next to them, and a checklist opens on focus with each rule drawing its check the moment it is met; it stays open while there is text, so the submit button never jumps away under your finger. The wand fills a random 16-character password, reveals it until you leave the field and scores it Strong. On a phone both buttons have 44px hit areas, iOS never zooms and the checklist scrolls into view above the keyboard.
Password Input is a Pro React component in the React input components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add password-input, together with Input, Field, Motion presets, useControllableState, useMediaQuery and 1 more and the npm packages motion and lucide-react.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add password-inputPassword Input is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import PasswordInput from @/components/ui/password-input.
import { PasswordInput, passwordRules } from "@/components/ui/password-input"
const rules = passwordRules({
minLength: 10,
labels: { length: (n) => "At least " + n + " characters", lower: "One lowercase letter", upper: "One uppercase letter", number: "One digit", symbol: "One symbol" },
})
export function SignUp() {
return (
<form className="flex flex-col gap-4">
<PasswordInput
name="password"
label="Password"
strength
rules={rules}
strengthLabels={["Too weak", "Weak", "Okay", "Good", "Strong"]}
generate
required
/>
</form>
)
}Props
labeldefault""ReactNodeThe label above the box, linked with htmlFor.
descriptiondefault""ReactNodeHelper text under the box, linked with aria-describedby. The error takes its place while it shows.
errordefault""ReactNodeReplaces the description, slides in and marks the field invalid.
requireddefaultfalsebooleanThe red mark after the label and the native required attribute.
disableddefaultfalsebooleanDims the field and blocks input and the reveal toggle; the generator hides.
invaliddefaultfalsebooleanThe red ring and aria-invalid without a message, when the form shows the error elsewhere.
readOnlydefaultfalsebooleanThe password stays selectable and can still be revealed, but cannot change; the generator hides. The demo fills in a sample value.
placeholderdefault""stringHint text while the field is empty.
defaultValuedefault""stringThe starting password while uncontrolled; value and onValueChange control it. The meter scores this first value until the field is focused, so a password manager filling the field never makes it flash.
showLabeldefault"Show password"stringThe toggle's aria-label and hover title while the password is hidden.
hideLabeldefault"Hide password"stringThe toggle's aria-label and hover title while the password shows.
capsLockLabeldefault"Caps Lock is on"ReactNodeThe warning under the box.
strengthCaptiondefault"Password strength"stringThe caption under the meter, left of the verdict, and the prefix screen readers hear.
generateLabeldefault"Generate a strong password"stringThe wand button's aria-label and hover title.
ruleMetLabeldefault"met"stringRead by screen readers after a met rule, visually hidden.
ruleUnmetLabeldefault"not met"stringRead by screen readers after a rule that is not met yet, visually hidden.
sizedefault"md""sm" | "md" | "lg"Height 32 / 40 / 48px like every field (md 44px on touch); the eye and wand buttons follow.
variantdefault"soft""soft" | "outline" | "underline" | "ghost"The field box look, shared with Input.
radiusdefault"md""none" | "sm" | "md" | "lg" | "full"Corner shape, scaled with the size; full makes a pill.
accentdefault""stringAny CSS color for the focus ring and the caret. Empty uses the ring token.
floatingLabeldefaultfalsebooleanThe label rests inside the box and floats up on focus or when filled, like Input.
defaultVisibledefaultfalsebooleanStarts with the password shown as text. Use visible and onVisibleChange to control it.
showToggledefaulttruebooleanThe eye button at the end of the box. It is a real button in the Tab order with aria-pressed and aria-controls; switching keeps the caret and selection.
strengthdefaultfalsebooleanTurns the field into a sign-up field: the four-bar meter with its verdict, the rules checklist and autoComplete new-password. The verdict is announced politely 500ms after typing stops.
showRulesdefault"focus""focus" | "always" | "never"When strength is on: the checklist opens on focus and stays while there is text (so the button under it never moves on blur), always shows, or never shows.
capsLockWarningdefaulttruebooleanReads Caps Lock from the key and pointer events while the field is focused and shows the warning (role status). Hidden on blur; phones never report it.
generatedefaultfalsebooleanA wand button before the eye: fills a random password from crypto.getRandomValues (no 0 O l 1 I, at least one lowercase, uppercase, digit and symbol, no runs), fires onChange like typing, and reveals it until focus leaves the field.
generateLengthdefault16numberLength of a generated password.
maxLengthdefault0numberThe native character limit, also applied to typing after a generated password. 0 means no limit.
visiblebooleanShown as text, controlled. Without onVisibleChange the toggle does nothing.
onVisibleChange(visible: boolean) => voidFires when the toggle, the generator or the blur after a generated password changes the visibility.
rulesPasswordRule[]The checklist, { id, label, test(password) }. Defaults to passwordRules(): at least 8 characters, a lowercase letter, an uppercase letter, a number, a symbol. The rule with id length also sets the minimum for the score.
score(password: string) => PasswordScoreReplaces the scorer, e.g. with zxcvbn loaded by the app. Defaults to scorePassword (see Parts), a quick guide rather than a guarantee.
strengthLabelsdefault"["Too weak", "Weak", "Fair", "Good", "Strong"]"[string, string, string, string, string]The verdict per score, default ["Too weak", "Weak", "Fair", "Good", "Strong"].
onGenerate(password: string) => voidCalled with the generated password, e.g. to offer a copy button.
showIconReactNodeThe toggle icon while hidden (Eye by default).
hideIconReactNodeThe toggle icon while shown (EyeOff by default).
generateIconReactNodeThe generator icon (WandSparkles by default).
autoCompletestringDefaults to "current-password", or "new-password" with strength or generate, so password managers save and suggest correctly. A manager's own icon may sit over the end of the box; there is room for it before the toggle.
enterKeyHint"enter" | "done" | "go" | "next" | "previous" | "search" | "send"The label of the phone keyboard's return key: "go" for a login field, "next" with strength (a sign-up form usually continues).
valuestringThe password, controlled, with onValueChange. Every other Input prop works too: name, onBlur, prefix, leftIcon, fieldProps... (not clearable, loading, showCount or rightIcon: the eye and wand own the end of the box).
onValueChange(value: string) => voidFires with the new password on every edit, including a generated one.
onChange(event: ChangeEvent<HTMLInputElement>) => voidThe native change event, untouched. A generated password fires it too, like typing.
prefixReactNodeText or an element before the input, in the muted addon look.
suffixReactNodeText or an element after the input, placed before the wand and eye buttons.
leftIconReactNodeA leading icon such as a lock; unsized svgs follow the size (14 / 16 / 18px).
fieldPropsPartial<FieldProps>Anything else for the Field wrapper, e.g. labelAction: <a href="/reset">Forgot password?</a>.
refRefObject<HTMLInputElement | null> or (node) => voidThe native input.
classNamesPartial<Record<InputSlot | "root" | "toggle" | "generate" | "strength" | "meter" | "segment" | "strengthLabel" | "rules" | "rule" | "capsLock", string>>Extra classes for the inner parts: the Input keys (box, input, label...) plus the password parts.
classNamestringClasses for the root wrapper around the field, the warning, the meter and the checklist.
Parts
passwordRules
functionBuilds the default checklist (length, lowercase, uppercase, number, symbol) with your minimum length and translated labels. Letters are Unicode aware, so é and Ø count.
minLengthdefault8numberThe length rule's minimum; also the length below which scorePassword returns 0.
labelsPartial<PasswordRuleLabels>Text per rule: length (a node or (min) => node), lower, upper, number, symbol.
returnsPasswordRule[]Rules to pass to the rules prop.
scorePassword
functionThe default strength score from 0 to 4: 0 when empty, short or common (password, qwerty...), +1 per met rule beyond length (max 3), +1 for 12+ characters, -1 for repeats or runs like 1234.
password*stringThe text to score.
rulesdefault"passwordRules()"PasswordRule[]The checklist; its length rule sets the minimum.
returns0 | 1 | 2 | 3 | 4The score the meter shows.
generatePassword
functionA random password with at least one lowercase letter, uppercase letter, digit and symbol, drawn with crypto.getRandomValues and free of look-alikes (0, O, l, 1, I). The wand button uses it.
lengthdefault16numberCharacters, clamped to 4 to 128.
returnsstringThe new password.
PasswordRule
typeOne checklist row: { id, label, test(password) => boolean }.
PasswordScore
typeThe strength score, 0 (too weak) to 4 (strong).
Examples
Sign-up with rules
Custom rule copy from passwordRules({ minLength: 10, labels }) and custom verdicts: the bars fill as you type and each rule draws its check when met.
Caps Lock warning
Turn Caps Lock on and type: an amber warning slides in under the box, and leaves when you turn it off or leave the field.
Generator
The wand fills a random 16-character password (no look-alike characters), reveals it until you leave the field and scores it strong; the copy button sits outside.
Confirm password
A second field checks the match on blur and turns green once both are the same.
Controlled visibility
visible and onVisibleChange driven by one checkbox for two fields, with showToggle off.
Sizes and variants
sm, md and lg, then outline with the generator, underline, and a ghost pill that starts visible.
Files
- components/ui/password-input.tsx
FAQ
Is the React Password Input component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Password Input?
Run npx wingo-ui@latest add password-input. It also adds the Wingo UI items it builds on (Input, Field, Motion presets, useControllableState, useMediaQuery and 1 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/password-input.
How does Password Input behave on phones?
On a phone both buttons have 44px hit areas, iOS never zooms and the checklist scrolls into view above the keyboard.
See also
Used in
More React input components
Articles using this component
- Shadcn Password Input: Show/Hide, Strength Meter, Caps Lock
Component guides9 min read
- Shadcn Login Page: Magic Link, Codes, 2FA and Recovery
Build it: screens and apps11 min read