probablybest
probablybest

Reputation: 1445

Click button trigger input to appear with focus

I have a hidden search bar that is made visible when you click on a button. When the search bar appears I would like the input to already have focus, so the user can immediately start typing.

I'm using $('#search-input').focus(); to try and achieve this on click but it isn't working.

Here is a JSFiddle. Click on the red box to trigger the search bar.

My Code:

$('#search-btn').on('click', function() {
  $(this).toggleClass('active');
  $('#search-input').focus();
  $('#search-wrapper').toggleClass('visible');

  if ($('#region-wrapper').hasClass('visible')) {
    $('#region-wrapper').toggleClass('visible');
  }

  if ($('#region-select').hasClass('active')) {
    $('#region-select').toggleClass('active');
  }
});
#menu-side {
  width: 200px;
  float: right;
  position: static;
  z-index: 10;
  margin-right: 15px;
  margin-top: 15px;
}

#search-btn {
  background: red;
  border: none;
  font-size: 1.8rem;
  cursor: pointer;
  outline: 0;
  position: relative;
  display: block;
  width: 40px;
  height: 40px;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-wrapper {
  width: 100%;
  position: absolute;
  top: 90px;
  left: 0;
  right: 0;
  opacity: 0;
  visibility: hidden;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-wrapper.visible {
  opacity: 1;
  visibility: visible !important;
}

#search-inner {
  background: #e5e5e5;
  padding: 35px 80px;
}

#search-input {
  border: none;
  background: none;
  font-size: 1.8rem;
  line-height: 1.8rem;
  color: black;
  float: left;
  width: 90%;
}

#search-submit {
  background: none;
  border: none;
  float: right;
  width: 10%;
  font-size: 1.8rem;
  outline: 0;
  transition-duration: 0.3s;
  transition-property: all;
  cursor: pointer;
  max-width: 21px;
  margin: 0;
  padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu-side" class="clearfix">
  <button id="search-btn" class="float-right js-overlay"><i class="fas fa-search float-right"></i></button>

  <div id="search-wrapper">
    <div class="container">
      <div id="search-inner" class="o-bdr-top">
        <form role="search" method="get" id="search-form" class="clearfix" action="">
          <button id="search-submit"><i class="fas fa-search float-right"></i></button>
          <input type="search" id="search-input" placeholder="What are you looking for?" name="s" class="float-left" />
        </form>
      </div>
    </div>
  </div>
</div>

Upvotes: 1

Views: 456

Answers (3)

Zakaria Acharki
Zakaria Acharki

Reputation: 67505

(From the official documentation) Take care to only use .focus() on elements that are visible.

You need just to wait for the toggle fired by toggleClass() to end so the #search-input input will be visible then you could perform the focus to the input.

Since toggleClass() method has no complete callback you could use setTimeout() for this like:

setTimeout(function() {
    $('#search-input').focus();
}, 100);

$('#search-input').focus();

$('#search-btn').on('click', function() {
  $(this).toggleClass('active');
  $('#search-wrapper').toggleClass('visible');

  if ($('#region-wrapper').hasClass('visible')) {
    $('#region-wrapper').toggleClass('visible');
  }

  if ($('#region-select').hasClass('active')) {
    $('#region-select').toggleClass('active');
  }
  setTimeout(function() {
    $('#search-input').focus();
  }, 100);
});
#menu-side {
  width: 200px;
  float: right;
  position: static;
  z-index: 10;
  margin-right: 15px;
  margin-top: 15px;
}

#search-btn {
  background: red;
  border: none;
  font-size: 1.8rem;
  cursor: pointer;
  outline: 0;
  position: relative;
  display: block;
  width: 40px;
  height: 40px;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-wrapper {
  width: 100%;
  position: absolute;
  top: 90px;
  left: 0;
  right: 0;
  opacity: 0;
  visibility: hidden;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-wrapper.visible {
  opacity: 1;
  visibility: visible !important;
}

#search-inner {
  background: #e5e5e5;
  padding: 35px 80px;
}

#search-input {
  border: none;
  background: none;
  font-size: 1.8rem;
  line-height: 1.8rem;
  color: black;
  float: left;
  width: 90%;
}

#search-submit {
  background: none;
  border: none;
  float: right;
  width: 10%;
  font-size: 1.8rem;
  outline: 0;
  transition-duration: 0.3s;
  transition-property: all;
  cursor: pointer;
  max-width: 21px;
  margin: 0;
  padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu-side" class="clearfix">
  <button id="search-btn" class="float-right js-overlay"><i class="fas fa-search float-right"></i></button>

  <div id="search-wrapper">
    <div class="container">
      <div id="search-inner" class="o-bdr-top">
        <form role="search" method="get" id="search-form" class="clearfix" action="">
          <button id="search-submit"><i class="fas fa-search float-right"></i></button>
          <input type="search" id="search-input" placeholder="What are you looking for?" name="s" class="float-left" />
        </form>
      </div>
    </div>
  </div>
</div>

Upvotes: 1

Zakaria Acharki
Zakaria Acharki

Reputation: 67505

I suggest the use of display instead of visibility/opacity and toggling the classes, you could use simply display: none by default then toggle the display using the jQuery toggle() method then the focus will work:

$('#search-input').focus();

$('#search-btn').on('click', function() {
  $(this).toggleClass('active');
  $('#search-wrapper').toggle();
  $('#search-input').focus();

  if ($('#region-wrapper').hasClass('visible')) {
    $('#region-wrapper').toggleClass('visible');
  }

  if ($('#region-select').hasClass('active')) {
    $('#region-select').toggleClass('active');
  }
  $('#search-input').toggleClass('active').focus();
});
#menu-side {
  width: 200px;
  float: right;
  position: static;
  z-index: 10;
  margin-right: 15px;
  margin-top: 15px;
}

#search-btn {
  background: red;
  border: none;
  font-size: 1.8rem;
  cursor: pointer;
  outline: 0;
  position: relative;
  display: block;
  width: 40px;
  height: 40px;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-wrapper {
  width: 100%;
  position: absolute;
  top: 90px;
  left: 0;
  right: 0;
  display: none;
  transition-duration: 0.3s;
  transition-property: all;
}

#search-inner {
  background: #e5e5e5;
  padding: 35px 80px;
}

#search-input {
  border: none;
  background: none;
  font-size: 1.8rem;
  line-height: 1.8rem;
  color: black;
  float: left;
  width: 90%;
}

#search-submit {
  background: none;
  border: none;
  float: right;
  width: 10%;
  font-size: 1.8rem;
  outline: 0;
  transition-duration: 0.3s;
  transition-property: all;
  cursor: pointer;
  max-width: 21px;
  margin: 0;
  padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu-side" class="clearfix">
  <button id="search-btn" class="float-right js-overlay"><i class="fas fa-search float-right"></i></button>

  <div id="search-wrapper">
    <div class="container">
      <div id="search-inner" class="o-bdr-top">
        <form role="search" method="get" id="search-form" class="clearfix" action="">
          <button id="search-submit"><i class="fas fa-search float-right"></i></button>
          <input type="search" id="search-input" placeholder="What are you looking for?" name="s" class="float-left" />
        </form>
      </div>
    </div>
  </div>
</div>

Upvotes: -1

Antonio Buelli
Antonio Buelli

Reputation: 59

The problem resides on input being hidden initially and browsers prevent operation such as focus on hidden elements. Common pratice, instead of using display: none, is to take the component off screen (IE: Fixed position with negative left and opacity === 0 or visibility hidden).

Using setTimeout (which in this case in undeterministic) is a bad pratice and should be avoided.

Upvotes: 1

Related Questions