Input Password
Password field with a show/hide toggle. Extends Input Group with no extra markup.
Examples
Show / hide toggle
A built-in eye button reveals the value — no extra markup needed.
Click the eye to reveal each field.
import { InputPassword } from "@codefast/ui/input-password";
import { Label } from "@codefast/ui/label";
export function InputPasswordFields() {
return (
<div className="w-full max-w-xs space-y-3">
<div className="grid gap-1.5">
<Label htmlFor="pw-current">Current password</Label>
<InputPassword id="pw-current" placeholder="••••••••" />
</div>
<div className="grid gap-1.5">
<Label htmlFor="pw-new">New password</Label>
<InputPassword id="pw-new" placeholder="Min. 8 characters" />
</div>
<p className="text-xs text-ui-muted">Click the eye to reveal each field.</p>
</div>
);
}
Live strength meter
Drive a strength bar from the controlled value as the user types.
Enter a password
import { InputPassword } from "@codefast/ui/input-password";
import { Label } from "@codefast/ui/label";
import { cn } from "@codefast/ui/lib/utils";
import type { ChangeEvent } from "react";
import { useState } from "react";
const LEVELS = [
{ label: "Too weak", color: "bg-rose-500" },
{ label: "Weak", color: "bg-amber-500" },
{ label: "Fair", color: "bg-yellow-500" },
{ label: "Strong", color: "bg-emerald-500" },
];
function score(value: string): number {
let points = 0;
if (value.length >= 8) {
points += 1;
}
if (/[A-Z]/.test(value) && /[a-z]/.test(value)) {
points += 1;
}
if (/\d/.test(value)) {
points += 1;
}
if (/[^A-Za-z0-9]/.test(value)) {
points += 1;
}
return Math.min(points, 4);
}
export function InputPasswordStrength() {
const [value, setValue] = useState("");
const points = score(value);
const level = points > 0 ? LEVELS[points - 1] : undefined;
return (
<div className="grid w-full max-w-xs gap-1.5">
<Label htmlFor="pw-strength">New password</Label>
<InputPassword
id="pw-strength"
placeholder="Type to test strength"
value={value}
onChange={(event: ChangeEvent<HTMLInputElement>) => setValue(event.target.value)}
/>
<div className="mt-1 flex gap-1">
{LEVELS.map((_, index) => (
<span
key={index}
className={cn(
"h-1 flex-1 rounded-full transition-colors",
index < points ? (level?.color ?? "bg-ui-border") : "bg-ui-border",
)}
/>
))}
</div>
<p className="text-xs text-ui-muted">{level ? level.label : "Enter a password"}</p>
</div>
);
}
Confirm match
Two fields with a live match check.
import { InputPassword } from "@codefast/ui/input-password";
import { Label } from "@codefast/ui/label";
import { useState } from "react";
export function InputPasswordConfirm() {
const [password, setPassword] = useState("");
const [confirm, setConfirm] = useState("");
const mismatch = confirm.length > 0 && password !== confirm;
return (
<div className="w-full max-w-xs space-y-3">
<div className="grid gap-1.5">
<Label htmlFor="pw-confirm-new">New password</Label>
<InputPassword
id="pw-confirm-new"
value={password}
onChange={(event) => {
setPassword(event.target.value);
}}
/>
</div>
<div className="grid gap-1.5">
<Label htmlFor="pw-confirm-repeat">Confirm password</Label>
<InputPassword
id="pw-confirm-repeat"
value={confirm}
aria-invalid={mismatch || undefined}
onChange={(event) => {
setConfirm(event.target.value);
}}
/>
{mismatch ? <p className="text-xs text-rose-500">Passwords don’t match.</p> : null}
</div>
</div>
);
}
Usage
The minimal import and composition — see Examples below for styled, real-world variants.
import { InputPassword } from "@codefast/ui/input-password";
export function InputPasswordUsage() {
return <InputPassword placeholder="••••••••" />;
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Built-in show/hide toggle — internally an InputGroupInput plus an InputGroupButton, no extra markup needed.
- The toggle’s aria-label swaps between "Show password" and "Hide password" as it’s clicked; it does not set aria-pressed.
- Forwards every native input prop except type, which the component manages internally.
API reference
Props for each part of the component. All native element props are also forwarded.
InputPassword
Extends Input with a reveal toggle. Forwards all native input props.
valuestringThe controlled value.
onChangeReact.ChangeEventHandler<HTMLInputElement>Called when the value changes.
disabledbooleanDisables the field and the toggle.
Default
false
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
- The reveal button relabels itself ("Show password" / "Hide password") as it toggles — that changing label, not aria-pressed, is what gets announced.
- Set autoComplete (current-password / new-password) to help password managers.
- Associate a Label via htmlFor / id.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Offer the reveal toggle so users can check what they typed.
- Show password requirements and live feedback on sign-up.
Don’t
- Don’t block paste — it breaks password managers.
- Don’t impose arbitrary maximum lengths.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.