Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JS .focus() only work inside a setTimeout of 50ms or longer

Tags:

javascript

Issue

I am creating a page at work for a client, with a slide out search bar. I want the focus (cursor) to move to the search bar (input) when I click a button that opens the search input field (it starts off hidden).

For some strange reason, the ONLY way I can seem to get the focus to switch the the input field is if I put it in a setTimeout with a minimum time of about 50ms (I tried 0, but doesn't work).

Weird caveat - I can momentarily that the input field gets focus/cursor when I close the search bar (click the open/close button that hides the search), but not when it opens, which is what I want. Unless it's in the setTimeout....

What I've tried

Setting the focus to something else, then blurring that, then setting the focus to my input field. [x]

  • Wrapping the .focus() in a setTimeout with 0 ms [x]

  • Setting the focus to a different, 'test' input field I created. [WORKS]

  • Adding tabindex to the input of -1 [x]

const icon = document.getElementById("search-icon");
const form = document.getElementById("search-form");
const input = document.getElementById("search-input");

icon.parentElement.addEventListener("click", e => {
  form.classList.toggle("visible");
  icon.classList.toggle("fa-search");
  icon.classList.toggle("fa-times");  

  setTimeout(() => input.focus(), 50);

});
<div class="header__search">
    <i id="search-icon" class="fas fa-search">click me</i>
    <form
      id="search-form"
      class="header__search-area"
      onclick="event.stopPropagation()"
    >
      <input
        id="search-input"
        tabindex="-1"
        type="text"
        placeholder="Enter Search Term..."
      />
      <button type="submit">search</button>
    </form>
</div>

For a quicker understanding, you click the icon (id=search-icon), and it displays the form alongside it which is position absolute and contains the 'input' I want to focus on.

If anyone can explain this, amazing. Google hath provideth nay answers.

like image 495
WillOSW Avatar asked Oct 16 '22 14:10

WillOSW


1 Answers

Because you've just clicked something and set the focus with your mouse, and then you are immediately changing it. The first time you focus (when you click) needs to complete first.

instead you click just change the focus immediately without a delay if you did it on the mouseup event instead, since that is when the mouse button is released. See below.


Edit

One second thought... I'm not really sure any more. copied your code and removed the delay, but it works just fine.

const icon = document.getElementById("search-icon");
const form = document.getElementById("search-form");
const input = document.getElementById("search-input");

icon.parentElement.addEventListener("click", e => {
  form.classList.toggle("visible");
  icon.classList.toggle("fa-search");
  icon.classList.toggle("fa-times");  
  
  input.focus();

});
<div class="header__search">
    <i id="search-icon" class="fas fa-search">click me</i>
    <form
      id="search-form"
      class="header__search-area"
      onclick="event.stopPropagation()"
    >
      <input
        id="search-input"
        tabindex="-1"
        type="text"
        placeholder="Enter Search Term..."
      />
      <button type="submit">search</button>
    </form>
</div>
like image 169
FiniteLooper Avatar answered Oct 20 '22 08:10

FiniteLooper