1

I have a popup button in my header. I need to make sure that when clicking outside its zone, the popup closes. How can i do this? In the code I'm trying to add remove active classes when clicking on body.active-search but it doesn't work.

const body = document.querySelector("body");
const searchButton = document.querySelector(".search-button");
const searchPopup = document.querySelector(".search-popup");

if (searchButton) {
  searchButton.addEventListener("click", () => {
    searchPopup.classList.toggle("active");
    searchButton.classList.toggle("active");
    body.classList.toggle("active-search");
  });
}

$(".active-search").click(function() {
  searchPopup.removeClass("active");
  searchButton.removeClass("active");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
  <div class="search-wrapper">
    <button class="search-button">Open Search</button>
    <div class="search-popup"></div>
  </div>
</header>
yanksi_
  • 125
  • 5
  • See: *Best practice Example* on this [closely related answer](https://stackoverflow.com/a/70691308/383904) – Roko C. Buljan Feb 09 '23 at 09:39
  • What is `$(".active-search")`? Can you please create a [mcve]? – Roko C. Buljan Feb 09 '23 at 09:41
  • `searchPopup.remove("active");` this is also wrong. You mean `searchPopup.classList.remove("active")`? You're mixing *vanilla* JavaScript with jQuery. PS, nowadays you don't necessarily need jQuery any more. The web and standards moved on. – Roko C. Buljan Feb 09 '23 at 09:41
  • 1
    $(".active-search") is the class that is attached to the body when the popup is open – yanksi_ Feb 09 '23 at 09:45
  • `body.classList`? You mean... `document.querySelector("body").classList` – Roko C. Buljan Feb 09 '23 at 09:46
  • Also `$(".active-search").click(` that class does not exist in the DOM at the time you assign the listener - you should learn how to use Event Delegation. Use instead: `$(document).on("click", ".active-search", function() {` – Roko C. Buljan Feb 09 '23 at 09:50
  • I don't understand why when I add code that removes the class when clicked outside the popup (I tried different options), it doesn't even open. Close immediately – yanksi_ Feb 09 '23 at 09:54

2 Answers2

1

On BODY "click" use Event.target.closest("selector") to determine if a click landed on specific elements selectors, if that's the case do nothing (return from the function); otherwise toggle the "active-search" class on BODY.
Also, there's no need to specifically toggle other active classes on elements. Use CSS instead.

const el = (sel, par) => (par??document).querySelector(sel);

const elSearchButton = el(".search-button");
const elSearchPopup = el(".search-popup");
const elBody = el("body");

elSearchButton.addEventListener("click", () => {
  elBody.classList.toggle("active-search");
});

elBody.addEventListener("click", (evt) => {
  // Do nothing if popup clicked or button
  if (evt.target.closest(".search-button, .search-popup")) return;
  // Else...
  elBody.classList.remove("active-search");
});
/*QuickReset*/ * {margin:0; box-sizing: border-box;}

body {
  min-height: 100vh;
}

.active-search {
  background: #eee;
}

.search-popup {
  display: none;
  padding: 1rem;
  background: gold;
}

.active-search .search-popup {
  display: block !important;
}
<header>
  <div class="search-wrapper">
    <button type="button" class="search-button">Toggle Search</button>
    <div class="search-popup"><input type="search" placeholder="Search..."></div>
  </div>
</header>

See this closely related answer: https://stackoverflow.com/a/70691308/383904

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
-1

Similar issue was described here Hide popup by clicking elsewhere

Basically you have to add a couple of code lines

$("body").click(function(){
  searchPopup.remove("active");
  searchButton.remove("active");
});

searchPopup.click(function(e){
  e.stopPropagation();
});

searchButton.click(function(e){
  e.stopPropagation();
});

Hope this helps.

Vsevolod
  • 3
  • 4
  • Stop using `Event.stopPropagation()` for good. (Well, unless for debugging, of if you really know what you're doing). An app and all its layers, yours or third-party, should be able at any time to respond to events. – Roko C. Buljan Feb 09 '23 at 09:35