2

I'm currently creating a Password field with an option to hide or display the password in React/Ionic.

  • I want to keep focus on the password field when you change the type of the input. (like PayPay Login page does) I'm doing it with event.preventDefault() on mousedown-Event.

const input = document.querySelector('input')

function toggleVisibility() {
  if (input.type === "text")
    input.type = "password"
  else
    input.type = "text"
}

function keepFocus(event) {
  event.preventDefault()
}
<input placeholder="Password" type="text">
<button onmousedown="keepFocus(event)" onclick="toggleVisibility()">Show Password</button>

Problem

  • When I change the type of the input field the cursor flips back to the start of the input field. I would like to keep the cursor where it was before. (Again like on PayPal)
Hey
  • 50
  • 6

1 Answers1

3

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;
    }
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Thanks for your detailed. Answer! Do you know a solution where you use the `onMouseDown preventDefault`-option which does not effect the cursor position? – Hey Dec 30 '21 at 18:52
  • @Hey You shouldn't be using `onmousedown` for this (as it's less accessible than `onclick'), so why are you asking? – Dai Dec 30 '21 at 18:53
  • @Hey I've updated my answer, it turns out `stopPropagation()` and `preventDefault()` are entirely unnecessary. – Dai Dec 30 '21 at 18:56
  • Great! Thanks for the update. I would like to use it in my react app and useRef with forwardRef makes the code a lot more "complex". A solution just with an event is much simpler. (So I think it's personal preference :) ) – Hey Dec 30 '21 at 18:58
  • @Hey If you're using React then you should not be touching the DOM directly at all, so my code won't help you there. – Dai Dec 30 '21 at 19:00
  • That's the reason. :) – Hey Dec 30 '21 at 19:00