1) “Show password” must be a real control
- Use a
<button type="button">, not a clickable icon<span>. - Give it an accessible name: visible text like “Show”/“Hide” works well.
- Reflect state with
aria-pressed="true|false"(or an explicit label change). - Associate the button to the field with
aria-controlsif helpful.
2) Keep focus stable when toggling password visibility
Switching type=password ↔ type=text can (depending on browser) reset cursor/selection or even shift focus.
- If the input was focused, restore focus after toggling.
- If possible, preserve selection (
selectionStart/selectionEnd), but treat it as best-effort. - Don’t move focus to the toggle button unless the user actually activates it.
3) Requirements UI: show it, but don’t announce on every keypress
A common mistake is updating requirements with aria-live on every input event. For many screen reader users, that becomes a nonstop stream of interruptions.
- It’s fine to update the checklist visually on each keystroke.
- Prefer announcements on blur or submit (“Requirements not met yet.” / “Looks good.”).
- For errors, use real inline error text +
aria-invalid+aria-describedbyto connect it.
4) Caps Lock warning should be polite
- If you detect Caps Lock, announce it via
role="status"/aria-live="polite". - Don’t use
role="alert"for Caps Lock — it’s not an emergency.
5) Be password-manager friendly
- Use the right
autocompletetokens:current-password,new-password. - Don’t disable paste; it breaks password managers and increases errors.
- Avoid weird requirements that block managers (e.g., banning long passwords).
Live example: Password fields demo.
Related: Form hints (aria-describedby), Inline errors, Error summaries.