@xsolla/xui-input-password
v0.209.1
Published
A cross-platform React password input component with visibility toggle, validation checkmark, and clear functionality. <!-- BEGIN:xui-mcp-instructions:input-password --> A specialised text input for password entry. Extends the standard input with password
Readme
Input Password
A cross-platform React password input component with visibility toggle, validation checkmark, and clear functionality.
A specialised text input for password entry. Extends the standard input with password-specific controls: a show/hide visibility toggle, an optional clear button, an optional check icon for password confirmation fields, and a right icons block that groups these controls. Always renders with type="password" semantics (masked by default) unless the user explicitly toggles visibility.
When to use
For any field where the user must enter a password — login, registration, account settings, password reset
For password confirmation fields (e.g. "Confirm new password") — use alongside the primary password field
When the form requires the user to create a new password and strength feedback is shown nearby
When not to use
- For non-sensitive text fields — use the standard Input component
- For PINs or short numeric codes — use a dedicated PIN input or a numeric Input with inputmode="numeric"
- When the input must always remain masked with no reveal option (e.g. a hardware security key PIN) — handle with a custom component that omits the visibility toggle
Content guidelines
Placeholder text — use Password or a format hint like At least 8 characters for create-password fields. Do not use verbose instructions as placeholder — they disappear when the user starts typing.
Field labels — always provide a visible label: "Password", "Current password", "New password", "Confirm new password". Do not rely on placeholder alone. Error messages — be specific:
- "Password is required"
- "Password must be at least 8 characters"
- "Password must contain at least one number and one special character"
- "Passwords do not match" (on the confirm field)
- "Incorrect password" (on the login form after a failed attempt)
- Visibility toggle label — the toggle icon button must have an accessible label that reflects the current state: aria-label="Show password" when masked, aria-label="Hide password" when revealed.
- Avoid password rules in error messages only — communicate password requirements upfront (e.g. in a helper text or a requirements list below the field) so users know the rules before they make a mistake.
Behaviour guidelines (from industry practice)
Default masking — the field must always render in masked state (Visibility=False) on mount, even if a value is pre-filled. Never initialise with Visibility=True.
Visibility toggle — clicking the eye icon toggles between masked and plain text. The toggle must work with mouse, touch, and keyboard (Enter/Space when the icon has focus). After toggling, focus must remain in the input field, not on the icon button.
Remove button — show the remove button only when the field has a value (Filled=True). Hide it in the empty state. Clicking removes the value and returns focus to the input.
Check icon right — update in real time as the user types in either password field. Show when values match, hide when they diverge. Do not show the check icon if either field is empty.
Autocomplete — use autocomplete="current-password" for login/current-password fields and autocomplete="new-password" for create-password/confirm-password fields. This allows password managers to fill and save credentials correctly and satisfies WCAG 1.3.5.
Password managers — do not block paste (onpaste prevention) in password fields. Password managers and users rely on paste. Blocking paste is a security anti-pattern and degrades usability significantly.
Validation timing — validate on blur (when the user leaves the field) or on form submit. Do not validate every keystroke. For "Confirm password" fields, re-validate when either field changes.
Error state — switch to State=Error with a specific error message on blur or submit:
- If the password does not meet requirements, show which requirement failed
- If passwords do not match, show the error on the confirm field (not the primary)
- Strength indicator — password strength feedback (e.g. a progress bar or label) lives outside the InputPassword component. Place it between the primary and confirm password fields.
- Caps Lock warning — optionally surface a Caps Lock indicator when the user has Caps Lock active in a masked field. Show it as a helper text below the field or a tooltip on the visibility icon.
- Disabled state — use State=Disable for fields that cannot be edited in the current context (e.g. a federated account where the password is managed externally). Always show a reason nearby.
Accessibility
The field must use type="password" in masked state and type="text" in revealed state. Never use type="text" permanently for a password field.
Provide a visible label via or aria-labelledby. Do not use placeholder as the only label.
Use autocomplete="current-password" or autocomplete="new-password" as appropriate — required for WCAG 1.3.5 (Identify Input Purpose).
The visibility toggle icon button must have a dynamic aria-label reflecting current state: "Show password" or "Hide password". It must also have aria-pressed (or aria-expanded) set appropriately, or use aria-label alone to communicate the current action.
When the field transitions to Visibility=True, announce the change to screen readers using aria-live="polite" on a visually hidden region (e.g. "Password is now visible").
The remove button (✕) must have aria-label="Clear password".
The check icon (✓) is status feedback — it must be wrapped in an aria-live="polite" region that announces "Passwords match" when it appears and "Passwords do not match" when it disappears.
When State=Error, the error message must be associated via aria-describedby so screen readers announce it when the field receives focus.
When State=Disable, the field must have aria-disabled="true".
The visibility toggle must be keyboard-operable: Tab to focus, Enter/Space to activate.
Installation
npm install @xsolla/xui-input-passwordDemo
Basic Password Input
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function BasicPassword() {
const [password, setPassword] = React.useState("");
return (
<InputPassword
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter password"
/>
);
}With Visibility Toggle
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function VisibilityToggle() {
const [password, setPassword] = React.useState("");
return (
<InputPassword
value={password}
onChange={(e) => setPassword(e.target.value)}
extraSee={true}
placeholder="Enter password"
/>
);
}With Validation
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function PasswordValidation() {
const [password, setPassword] = React.useState("");
return (
<InputPassword
value={password}
onChange={(e) => setPassword(e.target.value)}
extraSee={true}
extraCheckup={(pass) => pass.length >= 8}
label="Password"
helperText="At least 8 characters"
placeholder="Enter password"
/>
);
}With Error State
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function PasswordError() {
const [password, setPassword] = React.useState("");
return (
<InputPassword
value={password}
onChange={(e) => setPassword(e.target.value)}
extraSee={true}
error={password.length > 0 && password.length < 8}
errorMessage="Password must be at least 8 characters"
label="Password"
placeholder="Enter password"
/>
);
}Anatomy
import { InputPassword } from "@xsolla/xui-input-password";
<InputPassword
value={password} // Controlled value
onChange={handleChange} // Change handler (event)
onChangeText={handleText} // Change handler (string)
extraSee={true} // Show visibility toggle
extraClear={true} // Show clear button
extraCheckup={validateFn} // Validation function
label="Label" // Label above input
helperText="Help text" // Helper text below
error={boolean} // Error state
errorMessage="Error" // Error message
size="md" // Size variant
disabled={false} // Disabled state
/>;Examples
Full Featured Password
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function FullPassword() {
const [password, setPassword] = React.useState("");
const [error, setError] = React.useState("");
const validatePassword = (pass: string) => {
if (pass.length < 8) return false;
if (!/[A-Z]/.test(pass)) return false;
if (!/[0-9]/.test(pass)) return false;
return true;
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setPassword(value);
if (value && !validatePassword(value)) {
setError("Password must be 8+ chars with uppercase and number");
} else {
setError("");
}
};
return (
<InputPassword
value={password}
onChange={handleChange}
extraSee={true}
extraClear={true}
extraCheckup={validatePassword}
onRemove={() => setPassword("")}
label="Password"
helperText="8+ characters, uppercase, and number required"
error={!!error}
errorMessage={error}
placeholder="Create a strong password"
/>
);
}Password Sizes
import * as React from "react";
import { InputPassword } from "@xsolla/xui-input-password";
export default function PasswordSizes() {
return (
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<InputPassword size="xs" placeholder="Extra Small" extraSee />
<InputPassword size="sm" placeholder="Small" extraSee />
<InputPassword size="md" placeholder="Medium" extraSee />
<InputPassword size="lg" placeholder="Large" extraSee />
<InputPassword size="xl" placeholder="Extra Large" extraSee />
</div>
);
}API Reference
InputPassword
InputPassword Props:
| Prop | Type | Default | Description |
| :------------- | :------------------------------------- | :------ | :------------------------------------------------------------------------------------------------------------ |
| testID | string | — | Test ID for testing frameworks. On web this renders as data-testid; on React Native it renders as testID. |
| value | string | - | Controlled input value. |
| onChange | (e: ChangeEvent) => void | - | Change event handler. |
| onChangeText | (text: string) => void | - | Text change handler. |
| extraSee | boolean | false | Show visibility toggle button. |
| extraClear | boolean | false | Show clear button. |
| extraCheckup | (pass: string) => boolean | - | Validation function. |
| initialVisible | boolean | false | Initial password visibility. |
| size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | Component size. |
| label | string | - | Label above input. |
| helperText | string | - | Helper text below input. |
| error | boolean | false | Error state. |
| errorMessage | string | - | Error message. |
| disabled | boolean | false | Disabled state. |
| placeholder | string | - | Placeholder text. |
| name | string | - | Input name attribute. |
| onRemove | () => void | - | Clear button handler. |
| aria-label | string | - | Accessible label. |
| testID | string | - | Test identifier. |
Behavior
- Visibility Toggle: The eye icon reflects the current state of the password:
- Open eye = Password is currently visible (type="text")
- Closed eye = Password is currently hidden (type="password")
- This follows modern design system conventions (Material, Apple, Atlassian, Polaris)
- Checkmark appears when
extraCheckupreturns true - Clear button appears when input has value and
extraClearis true - Error state shows red border and error message
Accessibility
- Uses
type="password"ortype="text"based on visibility - Visibility toggle button has appropriate
aria-label:- "Show password" when password is hidden
- "Hide password" when password is visible
- Toggle button uses
aria-pressedto indicate current state - Error messages linked via
aria-describedbyfor screen reader context - Labels properly linked via
aria-labelledbywhen provided - Error messages use
role="alert"for immediate announcement
