Password Reveal Toggles: Where the Web Stands
HTML’s native password input is straightforward:
<input type="password">
Typing into it produces masked dots rather than readable characters:
••••••••
That masking is a basic shoulder-surfing defense. But modern UX has shifted toward giving users an explicit choice, typically via a ☑️ Reveal Password? checkbox. The reasoning is practical: if nobody is looking over your shoulder, showing the input lets you verify you typed a long, awkward password correctly instead of guessing after repeated failed attempts.
The question is how to implement that toggle cleanly.
Option 1: Runtime Type Switching
The dominant approach today is to start with type="password" and swap the input to type="text" when the user opts to reveal. It is the only method with reliable cross-browser support.
const input = document.querySelector(".password-input");
// When an input is checked, or whatever...
if (input.getAttribute("type") === "password") {
input.setAttribute("type", "text");
} else {
input.setAttribute("type", "password");
}
There is a real downside beyond the awkwardness of toggling a semantic attribute purely for display purposes: password managers. Tools that scan for and prefill password fields may be confused by an input that changes its type mid-flight — including the ones built into browsers. This is a known risk, though hard to pin down with precise failure cases.
Option 2: A CSS-Only Mask
The CSS property -webkit-text-security also masks input characters, and there was clearly an intent at some point to move masking into CSS. But support is inconsistent, and shipping a security-sensitive feature that only works in some browsers is a non-starter.
input[type="password"] {
-webkit-text-security: square;
}
form.show-passwords input[type="password"] {
-webkit-text-security: none;
}
Option 3: A Dedicated input-security Property
The CSS UI module has an Editor’s Draft spec for input-security, which would replace masking with a simple toggle value.
form.show-passwords input[type="password"] {
input-security: none;
}
That approach is clean and minimal. But no browser implements it yet, so in practice we remain on Option 1 for the foreseeable future.



