If you were to look at PayPal's own code which you linked to, you'd see it's just a matter of calling input.focus()
in a single event-listener:
function hidePassword(e) {
if (baseType === 'tel') {
$(field).addClass('tel-password');
} else {
field.setAttribute('type', 'password');
}
$(btnShow).removeClass('hide');
$(btnHide).addClass('hide');
field.focus();
e.stopPropagation();
login.logger.log({
evt: 'is_pwd_sh',
data: 'N',
instrument: true
});
login.logger.pushLogs();
}
Which can be simplified down to my example below, with some alterations:
- The default
type=""
should always be password
. Users expect password inputs to not suddenly show the password-they're-typing-in to everyone who can see their screens (especially when screen-sharing or projecting to a TV or giving a presentation, etc).
- I've changed the
querySelector
call to embedding the target <input type="password" />
in <button data-for="" />
to avoid problems caused by running querySelector
or getElementById
before the DOMContentLoaded
event, as is often the case with JS snippets people post around the Internet.
- The calls to
event.stopPropagation()
(in PayPal's code) or event.preventDefault()
(in your code) are superfluous and unnecessary. The important thing is calling input.focus()
in the same event-handler that changes the HTMLInputElement.type
property.
- Avoid using
onmousedown
with buttons. The 'click'
event works for all kinds of interactions (mouse, keyboard, touch, etc) while the 'mousedown'
and 'mouseclick'
events are only raised by actual mouse input (though often touch too).
function toggleVisibilityOnClick( event ) {
const button = event.currentTarget;
const input = document.getElementById( button.dataset['for'] );
if( !input ) throw new Error( "Couldn't find password input." );
if( input.type === 'text' ) {
input.type = 'password';
}
else {
input.type = 'text';
}
input.focus();
}
<input placeholder="Password" type="password" id="pwdInp" />
<button data-for="pwdInp" onclick="toggleVisibilityOnClick(event)">Show Password</button>
Microsoft's browsers have -ms-reveal
, which makes your toggle redundant, so you should hide the toggle in that case:
@supports selector(::-ms-reveal) {
input[type="password"] + button[data-for] {
display: none;
}
}