Password Interface
About
This demo shows a password input pattern with inline visual feedback for Shift and Caps Lock state, plus a press-and-hold show-password control. The implementation is plain JavaScript and uses page-scoped assets under content/example/password-interface.
It is useful when you want stronger login UX without framework dependencies.
Feedback Strategy
This page demonstrates two valid ways to convey password-state information: pure side icons and explanatory text below the field. Which one to use is a developer decision based on audience, accessibility goals, and UI density.
| Approach | Pros | Cons |
|---|---|---|
| Side Icons Only |
|
|
| Explanatory Text Below |
|
|
Examples
Password Input As Normal
Please enter your username and password:
Password Input With Feedback And Show Password Control
*iOS has its own Shift and CapsLock indicators in the keyboard so only the "Show Password" control is used on those devices. iOS also has it's own capslock indicator in the input field but it forgets the capslock state whenever the show password button is pressed/released, so that is hidden as well.
Simulating Autofill
This demo starts with a prefilled value to show first-interaction clearing behavior.
Security Hardening Notes
Client-Side (Demoed Here)
- Password fields are armed as
readonlyand unlocked on trusted interaction. - First trusted focus clears prefilled value in the hardened password demo inputs.
- Show-password is press-and-hold only, then automatically returns to masked state.
- Password values are cleared on
beforeunloadandpagehide. - Autocomplete semantics use
username+current-passwordfor login context.
Server-Side (Required In Production)
- Defend against XSS first: strict output escaping and strong CSP policy.
- Use secure session cookies:
HttpOnly,Secure, andSameSite. - Use CSRF protection for authenticated form posts.
- Rate-limit login attempts and add lockout/step-up checks.
- Never log raw passwords and never store reversible password data.
The Code
HTML
<div class="login login-feedback">
<div class="login__input login__password clearfix">
<label for="password-feedback">Password:</label>
<div class="login__input__container login__password__icons-container">
<input class="password__feedback" type="password" id="password-feedback">
<div class="login__password__icons noselect">
<div class="login__password__icon login__password__icons__shift login__password__icon--hidden" title="Shift key is active"></div>
<div class="login__password__icon login__password__icons__capslock login__password__icon--hidden" title="Caps Lock is active"></div>
<div class="login__password__icon login__password__icons__show login__password__icon--hidden" title="Press and hold to show password">
<button class="login__password__icon" type="button" title="Press and hold to show password" aria-label="Press and hold to show password"></button>
</div>
</div>
</div>
</div>
</div>CSS
.login__password__icons-container {
position: relative;
}
.login__password__icons {
position: absolute;
right: 0;
bottom: 0;
height: 100%;
pointer-events: none;
}
.login__password__icon {
display: inline-block;
height: 100%;
background-position: center;
background-repeat: no-repeat;
}
.login__password__icons__show button {
width: 40px;
height: 100%;
pointer-events: auto;
border: 0;
background-color: transparent;
cursor: pointer;
}
.login__password__icons .login__password__icons__shift::before {
font-family: "font-icon--example-password-interface";
color: #c59b48;
content: "\\E003";
}
.login__password__icons .login__password__icons__capslock::before {
font-family: "font-icon--example-password-interface";
color: #c54a48;
content: "\\E001";
}
.login__password__icons .login__password__icons__show button::before {
font-family: "font-icon--example-password-interface";
color: #3a87bd;
content: "\\E002";
}JavaScript
function armPasswordInput(input) {
input.setAttribute("readonly", "readonly");
function unlock(event) {
if (!event || event.isTrusted !== false) input.removeAttribute("readonly");
}
input.addEventListener("focusin", unlock);
input.addEventListener("pointerdown", unlock);
input.addEventListener("keydown", unlock);
}
function clearPasswordValues() {
document.querySelectorAll(".password__feedback").forEach(function (field) {
field.value = "";
});
}
window.addEventListener("beforeunload", clearPasswordValues);
window.addEventListener("pagehide", clearPasswordValues);Full implementation files: in/asset/css/content/example/password-interface.scss and in/asset/js/content/example/password-interface.js.
Attribution
This page is comprised of my own additions and either partially or heavily modified elements from the following source(s):