PasswordInput
Password field built on InputGroup with a show/hide toggle (aria-pressed), an optional strength meter and an optional requirement checklist.
Code
import { Field, FieldLabel, PasswordInput } from "@fadymondy/nasaq/web";export function SignInPassword() { return ( <Field> <FieldLabel>Password</FieldLabel> <PasswordInput autoComplete="current-password" /> </Field> );}Forms · beta
Live examples and controls: PasswordInput in the lab.
Install
npx shadcn@latest add https://docs.nasaqui.com/r/password-input.jsonA password field with an eye button that shows or hides the text, and an optional strength meter under it.
It is an InputGroup, so height, border, focus ring and invalid state match every
other field, and it works inside Field for the label, description and error.
When to use
- Sign in, sign up, change password, and any secret the person types and may want to check.
- Set
showStrengthwhen the person is choosing a new password.
When not to use
- One-time codes: use
OtpInput. - API keys or tokens you display read-only: use
CopyFieldfromCopyButton. - Plain text: use
InputfromField.
Import
import { PasswordInput } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"Quick start
import { Field, FieldLabel, PasswordInput } from "@fadymondy/nasaq/web";
export function SignInPassword() {
return (
<Field>
<FieldLabel>Password</FieldLabel>
<PasswordInput autoComplete="current-password" />
</Field>
);
}Anatomy
PasswordInput data-slot="password-input"
├─ InputGroup
│ ├─ InputGroupInput type="password" | "text"
│ └─ InputGroupAddon (end)
│ └─ Button data-slot="password-input-toggle", aria-pressed
├─ strength (only with showStrength) data-slot="password-input-strength", data-score="0".."4"
│ ├─ Meter data-slot="meter"
│ └─ level word aria-live="polite"
└─ ul (only with rules) data-slot="password-input-rules", aria-label="Password requirements"
└─ li × n data-met when met, Check or Minus icon, sr-only "met" / "not met"API
PasswordInput: every InputGroupInput prop except type (so autoComplete, name, value, defaultValue,
onChange, disabled, required, ltr and ref all pass through to the <input>), plus:
| Prop | Type | Default | Description |
|---|---|---|---|
visible | boolean | Controlled visibility. | |
defaultVisible | boolean | false | Initial visibility when uncontrolled. |
onVisibleChange | (visible: boolean) => void | Called when the toggle is pressed. | |
toggleLabel | string | "Show password" / "إظهار كلمة المرور" | Accessible name of the toggle. It does not change with state; aria-pressed does. |
showStrength | boolean | false | Show the strength meter and level word. |
score | number | estimator | Strength from 0 to 4. Rounded and clamped. Omit to use estimatePasswordStrength. |
strengthLabel | string | "Password strength" / "قوة كلمة المرور" | Name of the meter. |
strengthLevels | [string, string, string, string, string] | English or Arabic words | Words for scores 0 to 4. |
rules | boolean | PasswordPolicy | readonly PasswordRule[] | Show a requirement checklist. true is 12 characters plus upper, lower, digit and symbol; a policy changes that; an array is shown as is. | |
ruleLabels | Record<string, string> | English or Arabic | Text per rule id. Needed for custom ids. |
className | string | Class for the outer wrapper. | |
inputClassName | string | Class for the <input>. |
estimatePasswordStrength(password: string): PasswordScore: a small estimate from length and character classes.
Returns 0 to 4. PasswordScore is 0 | 1 | 2 | 3 | 4. It is a hint, not a policy.
| Score | Rule |
|---|---|
| 0 | Empty, shorter than 6, or three or fewer distinct characters |
| 1 | 6 or more characters |
| 2 | 8 or more characters with two classes |
| 3 | 10 or more characters with three classes |
| 4 | 12 or more with four classes, or 16 or more with three |
Classes are lower case, upper case, digit, symbol, and uncased letters such as Arabic.
computePasswordRules(password, policy?): PasswordRule[]: the length rule (with min) then one rule per class in
policy.require (default upper, lower, digit, symbol). PasswordPolicy is { minLength?: number; require?: ("upper" | "lower" | "digit" | "symbol")[] }, minimum 12 by default. PasswordRule is { id; met: boolean; min?: number }.
computeRuleScore(rules): PasswordScore: 0 until length passes, then 1 plus one per other rule met, capped at 4.
Pass it as score so the meter follows your policy instead of the estimate.
passwordMeetsPolicy(rules): boolean: true when every rule is met. Use it to block submit.
Examples
Sign up with the estimator
import { Field, FieldDescription, FieldLabel, PasswordInput } from "@fadymondy/nasaq/web";
export function NewPassword() {
return (
<Field>
<FieldLabel>New password</FieldLabel>
<PasswordInput autoComplete="new-password" showStrength />
<FieldDescription>At least 8 characters.</FieldDescription>
</Field>
);
}Your own estimator
import { PasswordInput } from "@fadymondy/nasaq/web";
import { useState } from "react";
// zxcvbn(value).score is already 0 to 4.
declare function zxcvbnScore(value: string): number;
export function Custom() {
const [value, setValue] = useState("");
return <PasswordInput showStrength value={value} score={zxcvbnScore(value)} onChange={(e) => setValue(e.target.value)} />;
}A policy checklist
import { PasswordInput, computePasswordRules, computeRuleScore, passwordMeetsPolicy } from "@fadymondy/nasaq/web";
import { useState } from "react";
export function Policy() {
const [value, setValue] = useState("");
const rules = computePasswordRules(value, { minLength: 10 });
return (
<form onSubmit={(e) => passwordMeetsPolicy(rules) || e.preventDefault()}>
<PasswordInput autoComplete="new-password" showStrength score={computeRuleScore(rules)} rules={rules} value={value} onChange={(e) => setValue(e.target.value)} />
</form>
);
}Arabic
import { Field, FieldLabel, PasswordInput } from "@fadymondy/nasaq/web";
export function ArabicPassword() {
return (
<Field>
<FieldLabel>كلمة مرور جديدة</FieldLabel>
<PasswordInput autoComplete="new-password" showStrength placeholder="أدخل كلمة المرور" />
</Field>
);
}Accessibility
| Key | Action |
|---|---|
| Tab | Moves from the input to the toggle. |
| Enter / Space on the toggle | Shows or hides the password. |
- The toggle is a
buttonwith a constantaria-labelandaria-pressedfor the state, so a screen reader says "Show password, toggle button, pressed" and never a contradicting label. - The meter is
role="meter"witharia-valuenow0 to 4 and anaria-label. The level word sits in anaria-live="polite"region, so it is spoken when it changes. - Caller must localise:
toggleLabel,strengthLabelandstrengthLevelswhen not using English or Arabic. - The checklist is a labelled list. Each item ends with a visually hidden ", met" or ", not met", so the state is not carried by the tick or the colour alone. It is not live: re-reading on every key would be noisy. Show the unmet rule in the field error on submit.
- Set
autoCompleteso password managers work:current-passwordto sign in,new-passwordto create one. - The input sets
autoCapitalize="none",autoCorrect="off"andspellCheck={false}.
RTL & i18n
- The toggle sits at the inline end: the right in English, the left in Arabic. The meter fills from the inline start.
- The value keeps the input's natural direction and is not mirrored. Pass
ltrto pin the typed value to left-to-right in an Arabic form, which keeps symbols in order. - Built-in English and Arabic strings follow the Nasaq locale.
- The estimator counts code points, so Arabic letters and emoji are one character each.
Styling & tokens
- Border, radius, focus ring:
--nq-*tokens throughInputGroup. Meter fill uses the danger, warning, info and success tokens. - Target
[data-slot="password-input-strength"][data-score="3"]to style by score. aria-invalidturns the border to the danger colour. Extend withclassNameandinputClassName.
Do / Don't
- Do set
autoCompleteon every password field. - Do use the meter only when creating a password.
- Don't rely on the estimator as a security rule: enforce the policy on the server.
- Don't put a strength meter on a sign-in form.
Related
InputGroupFieldProgress(Meter)OtpInput
Lab
https://docs.nasaqui.com/?path=/docs/components-forms-password-input--docs
OtpInput
One-time-code entry with N boxes; paste fills every box, Backspace steps back, digits stay left-to-right in RTL.
PhoneInput
Phone number field with a searchable country list (SVG flag, name in English or Arabic, calling code; Gulf and Arab countries first) and a digits input that groups the number as you type. The value is E.164.