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.