xpuu
xpuu

Reputation: 1640

Unable to focus DOM element in touch events

When I call input.focus() from the touch event listener it focuses the input for a few ms, but focus is given immediately back to the touched element. I tested that also on my phone (real touch device) and the behavior is the same. I tried to google some documentation about that, but didn't find anything useful.

The only current workaround I use is setTimeout(() => input.focus(), 500), which is pretty sloppy way to do this. Any ideas?

https://codepen.io/xpuu/pen/BXpBZY

document.addEventListener("DOMContentLoaded", function() {
  let input = document.getElementById("test");

  let events = {
    click(e) {
      console.log("click");
      input.focus();
    },
    touchstart(e) {
      console.log("touchstart");
      input.focus();
    },
    touchend(e) {
      console.log("touchend");
      input.focus();
    },
    touchprevent(e) {
      console.log("touchprevent");
      e.preventDefault();
      input.focus();
    },
    touchtimeout(e) {
      console.log("touchtimeout");
      setTimeout(() => input.focus(), 500);
    }
  };

  let buttons = document.getElementById("buttons");
  let validEvents = ["click", "touchstart", "touchend"];

  Object.keys(events).forEach(key => {
    let handler = key;
    let btn = document.createElement("button");
    btn.innerText = key;
    if (!validEvents.includes(handler)) {
      handler = "touchstart";
    }
    //console.log(handler, key);
    btn.addEventListener(handler, events[key]);
    buttons.appendChild(btn);
  });
});
input {
  padding: 3px;
}
<p>Enable devtools / responsive mode and touch emulation for this to work</p>
<input id="test" value="focus me please">
<p id="buttons"></p>

Upvotes: 2

Views: 1324

Answers (1)

xpuu
xpuu

Reputation: 1640

As Chris mentioned, you have to run e.preventDefault() before focusing the input. Also it's important to disable passive handler in the addEventListener options.

let touchprevent = e => {
  console.log("touchprevent");
  e.preventDefault();
  input.focus();
}
input.addEventListener('touchstart', touchprevent, { passive: false });

Upvotes: 2

Related Questions