skip to Main Content

I have created a search box like this code.
When I click outside the search box, I want it to close.
But in my code, when I click on Input for writing or the content inside the search box, the search box closes.

Could you guide me to where my code is wrong?

Thank you in advance for your cooperation.

const searchIcon = document.querySelector("#searchIcon");
const searchContent = document.querySelector( ".searchForm--content");
searchIcon.addEventListener("click", function() {
    searchContent.classList.toggle("active");
});


window.onclick = function(event) {
  if (!event.target.matches('#searchIcon') ) {    
   var searchContent=document.querySelector(".searchForm--content");
     var searchFormInput=document.querySelector("searchForm--content.active > .searchForm--content__input");
     if(searchContent.classList.contains('active') && !event.target.contains(searchFormInput)){
          searchContent.classList.remove('active');
      }
  }
}
.searchForm--content{
    position: relative
}

#searchIcon{
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

.searchForm > img {
  cursor: pointer;
  width: auto;
  vertical-align: middle;
}

.searchForm--content{
  border: 1px solid blue;
  border-radius: 10px;
  padding-inline:0.75rem;
  color: black;
  position: absolute;
  left: 12px;
  width: 40%;
  top: 70px;
  display: none;
  align-items: center;
  justify-content: space-between;
}
.searchForm--content.active {
  display: flex;
} 

.searchForm--content .btn{
    position: absolute;
    left:0.2rem;
    top:50%;
    transform: translatey(-50%);
}
.searchForm--content input[type="search"]{
    width: 65%;
    border: 1px solid red;
    padding: 1rem 0.5rem;
    color: black;
  margin-left: auto;
}
<form class="searchForm" role="search">
  <div id="searchIcon">my icon search</div>
  
    <div class="searchForm--content" id="my-box">
        <input type="search" placeholder="search" name="s" inputmode="search"  class="searchForm--content__input" /> 
        <button type="submit" class="btn btn--blue" >submit</button>
    </div>
</form>

3

Answers


  1. Your issue is that whenever you click on an element, the click event fires for not only that element, but also all of its parent elements. So, a click event handler on window will fire for any click anywhere on the page.

    To stop a click event from going to other event handlers like this, you can call the event.stopImmediatePropagation() method. Just use it like this:

    const searchIcon = document.querySelector("#searchIcon");
    const searchContent = document.querySelector(".searchForm--content");
    searchIcon.addEventListener("click", function() {
      searchContent.classList.toggle("active");
    });
    
    searchContent.addEventListener('click', function(event) {
      event.stopImmediatePropagation();
    });
    
    window.onclick = function(event) {
      if (!event.target.matches('#searchIcon')) {
        var searchContent = document.querySelector(".searchForm--content");
        var searchFormInput = document.querySelector("searchForm--content.active > .searchForm--content__input");
        if (searchContent.classList.contains('active') && !event.target.contains(searchFormInput)) {
          searchContent.classList.remove('active');
        }
      }
    }
    .searchForm--content {
      position: relative
    }
    
    #searchIcon {
      background-color: green;
      color: white;
      padding: 12px;
      width: fit-content;
    }
    
    .searchForm>img {
      cursor: pointer;
      width: auto;
      vertical-align: middle;
    }
    
    .searchForm--content {
      border: 1px solid blue;
      border-radius: 10px;
      padding-inline: 0.75rem;
      color: black;
      position: absolute;
      left: 12px;
      width: 40%;
      top: 70px;
      display: none;
      align-items: center;
      justify-content: space-between;
    }
    
    .searchForm--content.active {
      display: flex;
    }
    
    .searchForm--content .btn {
      position: absolute;
      left: 0.2rem;
      top: 50%;
      transform: translatey(-50%);
    }
    
    .searchForm--content input[type="search"] {
      width: 65%;
      border: 1px solid red;
      padding: 1rem 0.5rem;
      color: black;
      margin-left: auto;
    }
    <form class="searchForm" role="search">
      <div id="searchIcon">my icon search</div>
    
      <div class="searchForm--content" id="my-box">
        <input type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
        <button type="submit" class="btn btn--blue">submit</button>
      </div>
    </form>
    Login or Signup to reply.
  2. The problem is this that you are just matching the div with id searchIcon. So, when you click that div, the search Form Content show. But when you click on search input field, it close the search Form Content, because you are not matching search input field in if condition. So, you have to update the if condition. Here is the updated answer:-

    const searchIcon = document.querySelector("#searchIcon");
    const searchContent = document.querySelector( ".searchForm--content");
    searchIcon.addEventListener("click", function() {
        searchContent.classList.toggle("active");
    });
    
    
    window.onclick = function(event) {
      console.log(event.target.matches('#searchIcon'))
      if (!(event.target.matches('#searchIcon') ||  event.target.matches('.searchForm--content__input'))) {    
       var searchContent=document.querySelector(".searchForm--content");
         var searchFormInput=document.querySelector("searchForm--content.active > .searchForm--content__input");
         if(searchContent.classList.contains('active') && !event.target.contains(searchFormInput)){
              searchContent.classList.remove('active');
          }
      }
    }
    .searchForm--content{
        position: relative
    }
    
    #searchIcon{
      background-color: green;
      color: white;
      padding: 12px;
      width: fit-content;
    }
    
    .searchForm > img {
      cursor: pointer;
      width: auto;
      vertical-align: middle;
    }
    
    .searchForm--content{
      border: 1px solid blue;
      border-radius: 10px;
      padding-inline:0.75rem;
      color: black;
      position: absolute;
      left: 12px;
      width: 40%;
      top: 70px;
      display: none;
      align-items: center;
      justify-content: space-between;
    }
    .searchForm--content.active {
      display: flex;
    } 
    
    .searchForm--content .btn{
        position: absolute;
        left:0.2rem;
        top:50%;
        transform: translatey(-50%);
    }
    .searchForm--content input[type="search"]{
        width: 65%;
        border: 1px solid red;
        padding: 1rem 0.5rem;
        color: black;
      margin-left: auto;
    }
    <form class="searchForm" role="search">
      <div id="searchIcon">my icon search</div>
      
        <div class="searchForm--content" id="my-box">
            <input type="search" placeholder="search" name="s" inputmode="search"  class="searchForm--content__input" /> 
            <button type="submit" class="btn btn--blue" >submit</button>
        </div>
    </form>

    In this way, when you click submit button, it will close the search Form content. That’s good. So, only clicking on search field and div with id searchIcon will not close the searchForm content.

    Login or Signup to reply.
  3. Your condition in the EventListener doesn’t check at all whether your click happened inside the textbox. You’re only checking for #searchIcon.

    Updated snippet:

    const searchIcon = document.querySelector("#searchIcon");
    const searchContent = document.querySelector(".searchForm--content");
    searchIcon.addEventListener("click", function() {
      searchContent.classList.toggle("active");
    });
    
    
    window.onclick = function(event) {
      if (!(event.target.closest('#searchIcon') || event.target.closest('#my-box'))) {
        var searchContent = document.querySelector(".searchForm--content");
        var searchFormInput = document.querySelector(
          "searchForm--content.active > .searchForm--content__input");
        if (searchContent.classList.contains('active') && !event.target.contains(searchFormInput)) {
          searchContent.classList.remove('active');
        }
      }
    }
    .searchForm--content {
      position: relative
    }
    
    #searchIcon {
      background-color: green;
      color: white;
      padding: 12px;
      width: fit-content;
    }
    
    .searchForm>img {
      cursor: pointer;
      width: auto;
      vertical-align: middle;
    }
    
    .searchForm--content {
      border: 1px solid blue;
      border-radius: 10px;
      padding-inline: 0.75rem;
      color: black;
      position: absolute;
      left: 12px;
      width: 40%;
      top: 70px;
      display: none;
      align-items: center;
      justify-content: space-between;
    }
    
    .searchForm--content.active {
      display: flex;
    }
    
    .searchForm--content .btn {
      position: absolute;
      left: 0.2rem;
      top: 50%;
      transform: translatey(-50%);
    }
    
    .searchForm--content input[type="search"] {
      width: 65%;
      border: 1px solid red;
      padding: 1rem 0.5rem;
      color: black;
      margin-left: auto;
    }
    <form class="searchForm" role="search">
      <div id="searchIcon">my icon search</div>
    
      <div class="searchForm--content" id="my-box">
        <input id="inputSearch" type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
        <button type="submit" class="btn btn--blue">submit</button>
      </div>
    </form>

    Notice that I used event.target.closest instead of matches so that the it checks against #my-box and all of its children so you don’t need to worry about checking against each element in that area. Got inspiration for that from this answer by @AuxTaco

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search