I have some HTML menus, which I show completely when a user clicks on the head of these menus. I would like to hide these elements when the user clicks outside the menus' area.
Is something like this possible with jQuery?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
event.path
. http://stackoverflow.com/questions/152975/how-do-i-detect-a-click-outside-an-element/43405204#43405204 - anyone event.target
and without event.stopPropagation
. - anyone Note: Using
stopPropagation
is something that should be avoided as it breaks normal event flow in the DOM. See this CSS Tricks article for more information. Consider using this method instead.
Attach a click event to the document body which closes the window. Attach a separate click event to the container which stops propagation to the document body.
$(window).click(function() {
//Hide the menus if visible
});
$('#menucontainer').click(function(event){
event.stopPropagation();
});
Answered 2023-09-20 20:23:08
$('html').click()
not body. The body always has the height of its content. It there is not a lot of content or the screen is very high, it only works on the part filled by the body. - anyone You can listen for a click event on document
and then make sure #menucontainer
is not an ancestor or the target of the clicked element by using .closest()
.
If it is not, then the clicked element is outside of the #menucontainer
and you can safely hide it.
$(document).click(function(event) {
var $target = $(event.target);
if(!$target.closest('#menucontainer').length &&
$('#menucontainer').is(":visible")) {
$('#menucontainer').hide();
}
});
You can also clean up after the event listener if you plan to dismiss the menu and want to stop listening for events. This function will clean up only the newly created listener, preserving any other click listeners on document
. With ES2015 syntax:
export function hideOnClickOutside(selector) {
const outsideClickListener = (event) => {
const $target = $(event.target);
if (!$target.closest(selector).length && $(selector).is(':visible')) {
$(selector).hide();
removeClickListener();
}
}
const removeClickListener = () => {
document.removeEventListener('click', outsideClickListener);
}
document.addEventListener('click', outsideClickListener);
}
For those who don't want to use jQuery. Here's the above code in plain vanillaJS (ECMAScript6).
function hideOnClickOutside(element) {
const outsideClickListener = event => {
if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
element.style.display = 'none';
removeClickListener();
}
}
const removeClickListener = () => {
document.removeEventListener('click', outsideClickListener);
}
document.addEventListener('click', outsideClickListener);
}
const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
NOTE:
This is based on Alex comment to just use !element.contains(event.target)
instead of the jQuery part.
But element.closest()
is now also available in all major browsers (the W3C version differs a bit from the jQuery one).
Polyfills can be found here: Element.closest()
In the case where you want the user to be able to click-and-drag inside the element, then release the mouse outside the element, without closing the element:
...
let lastMouseDownX = 0;
let lastMouseDownY = 0;
let lastMouseDownWasOutside = false;
const mouseDownListener = (event: MouseEvent) => {
lastMouseDownX = event.offsetX;
lastMouseDownY = event.offsetY;
lastMouseDownWasOutside = !$(event.target).closest(element).length;
}
document.addEventListener('mousedown', mouseDownListener);
And in outsideClickListener
:
const outsideClickListener = event => {
const deltaX = event.offsetX - lastMouseDownX;
const deltaY = event.offsetY - lastMouseDownY;
const distSq = (deltaX * deltaX) + (deltaY * deltaY);
const isDrag = distSq > 3;
const isDragException = isDrag && !lastMouseDownWasOutside;
if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null
element.style.display = 'none';
removeClickListener();
document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener()
}
}
Answered 2023-09-20 20:23:08
!element.contains(event.target)
using Node.contains() - anyone How to detect a click outside an element?
The reason that this question is so popular and has so many answers is that it is deceptively complex. After almost eight years and dozens of answers, I am genuinely surprised to see how little care has been given to accessibility.
I would like to hide these elements when the user clicks outside the menus' area.
This is a noble cause and is the actual issue. The title of the question—which is what most answers appear to attempt to address—contains an unfortunate red herring.
Hint: it's the word "click"!
If you're binding click handlers to close the dialog, you've already failed. The reason you've failed is that not everyone triggers click
events. Users not using a mouse will be able to escape your dialog (and your pop-up menu is arguably a type of dialog) by pressing Tab, and they then won't be able to read the content behind the dialog without subsequently triggering a click
event.
So let's rephrase the question.
How does one close a dialog when a user is finished with it?
This is the goal. Unfortunately, now we need to bind the userisfinishedwiththedialog
event, and that binding isn't so straightforward.
So how can we detect that a user has finished using a dialog?
focusout
eventA good start is to determine if focus has left the dialog.
Hint: be careful with the blur
event, blur
doesn't propagate if the event was bound to the bubbling phase!
jQuery's focusout
will do just fine. If you can't use jQuery, then you can use blur
during the capturing phase:
element.addEventListener('blur', ..., true);
// use capture: ^^^^
Also, for many dialogs you'll need to allow the container to gain focus. Add tabindex="-1"
to allow the dialog to receive focus dynamically without otherwise interrupting the tabbing flow.
$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});
$('div').on('focusout', function () {
$(this).removeClass('active');
});
div {
display: none;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>
If you play with that demo for more than a minute you should quickly start seeing issues.
The first is that the link in the dialog isn't clickable. Attempting to click on it or tab to it will lead to the dialog closing before the interaction takes place. This is because focusing the inner element triggers a focusout
event before triggering a focusin
event again.
The fix is to queue the state change on the event loop. This can be done by using setImmediate(...)
, or setTimeout(..., 0)
for browsers that don't support setImmediate
. Once queued it can be cancelled by a subsequent focusin
:
$('.submenu').on({
focusout: function (e) {
$(this).data('submenuTimer', setTimeout(function () {
$(this).removeClass('submenu--active');
}.bind(this), 0));
},
focusin: function (e) {
clearTimeout($(this).data('submenuTimer'));
}
});
$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});
$('div').on({
focusout: function () {
$(this).data('timer', setTimeout(function () {
$(this).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this).data('timer'));
}
});
div {
display: none;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>
The second issue is that the dialog won't close when the link is pressed again. This is because the dialog loses focus, triggering the close behavior, after which the link click triggers the dialog to reopen.
Similar to the previous issue, the focus state needs to be managed. Given that the state change has already been queued, it's just a matter of handling focus events on the dialog triggers:
This should look familiar$('a').on({
focusout: function () {
$(this.hash).data('timer', setTimeout(function () {
$(this.hash).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('timer'));
}
});
$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});
$('div').on({
focusout: function () {
$(this).data('timer', setTimeout(function () {
$(this).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this).data('timer'));
}
});
$('a').on({
focusout: function () {
$(this.hash).data('timer', setTimeout(function () {
$(this.hash).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('timer'));
}
});
div {
display: none;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>
If you thought you were done by handling the focus states, there's more you can do to simplify the user experience.
This is often a "nice to have" feature, but it's common that when you have a modal or popup of any sort that the Esc key will close it out.
keydown: function (e) {
if (e.which === 27) {
$(this).removeClass('active');
e.preventDefault();
}
}
$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});
$('div').on({
focusout: function () {
$(this).data('timer', setTimeout(function () {
$(this).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this).data('timer'));
},
keydown: function (e) {
if (e.which === 27) {
$(this).removeClass('active');
e.preventDefault();
}
}
});
$('a').on({
focusout: function () {
$(this.hash).data('timer', setTimeout(function () {
$(this.hash).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('timer'));
}
});
div {
display: none;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>
If you know you have focusable elements within the dialog, you won't need to focus the dialog directly. If you're building a menu, you could focus the first menu item instead.
click: function (e) {
$(this.hash)
.toggleClass('submenu--active')
.find('a:first')
.focus();
e.preventDefault();
}
$('.menu__link').on({
click: function (e) {
$(this.hash)
.toggleClass('submenu--active')
.find('a:first')
.focus();
e.preventDefault();
},
focusout: function () {
$(this.hash).data('submenuTimer', setTimeout(function () {
$(this.hash).removeClass('submenu--active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('submenuTimer'));
}
});
$('.submenu').on({
focusout: function () {
$(this).data('submenuTimer', setTimeout(function () {
$(this).removeClass('submenu--active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this).data('submenuTimer'));
},
keydown: function (e) {
if (e.which === 27) {
$(this).removeClass('submenu--active');
e.preventDefault();
}
}
});
.menu {
list-style: none;
margin: 0;
padding: 0;
}
.menu:after {
clear: both;
content: '';
display: table;
}
.menu__item {
float: left;
position: relative;
}
.menu__link {
background-color: lightblue;
color: black;
display: block;
padding: 0.5em 1em;
text-decoration: none;
}
.menu__link:hover,
.menu__link:focus {
background-color: black;
color: lightblue;
}
.submenu {
border: 1px solid black;
display: none;
left: 0;
list-style: none;
margin: 0;
padding: 0;
position: absolute;
top: 100%;
}
.submenu--active {
display: block;
}
.submenu__item {
width: 150px;
}
.submenu__link {
background-color: lightblue;
color: black;
display: block;
padding: 0.5em 1em;
text-decoration: none;
}
.submenu__link:hover,
.submenu__link:focus {
background-color: black;
color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu">
<li class="menu__item">
<a class="menu__link" href="#menu-1">Menu 1</a>
<ul class="submenu" id="menu-1" tabindex="-1">
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
</ul>
</li>
<li class="menu__item">
<a class="menu__link" href="#menu-2">Menu 2</a>
<ul class="submenu" id="menu-2" tabindex="-1">
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
<li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
</ul>
</li>
</ul>
lorem ipsum <a href="http://example.com/">dolor</a> sit amet.
This answer hopefully covers the basics of accessible keyboard and mouse support for this feature, but as it's already quite sizable I'm going to avoid any discussion of WAI-ARIA roles and attributes, however I highly recommend that implementers refer to the spec for details on what roles they should use and any other appropriate attributes.
Answered 2023-09-20 20:23:08
You don't actually want to bind click handlers.
You can bind click handlers and also handle cases where users doesn't have a mouse. It doesn't hurt accessibility, it only adds functionality to users with a mouse. Adding functionality to one group of users doesn't hurt the users who can't use that functionality. You can provide more than one way of closing a diablog This is actually a pretty common logical fallacy. It's totally fine to give a feature to one group of users even when others don't benefit. I agree that all users should be able to have a good experience though - anyone blur
or focusout
handlers, you will still fully support mouse and touch users, and it has the added benefit of supporting keyboard users. At no point did I suggest that you ought to not support mouse users. - anyone The other solutions here didn't work for me so I had to use:
if(!$(event.target).is('#foo'))
{
// hide menu
}
I used this method to handle closing a drop down menu when clicking outside of it.
First, I created a custom class name for all the elements of the component. This class name will be added to all elements that make up the menu widget.
const className = `dropdown-${Date.now()}-${Math.random() * 100}`;
I create a function to check for clicks and the class name of the clicked element. If clicked element does not contain the custom class name I generated above, it should set the show
flag to false
and the menu will close.
const onClickOutside = (e) => {
if (!e.target.className.includes(className)) {
show = false;
}
};
Then I attached the click handler to the window object.
// add when widget loads
window.addEventListener("click", onClickOutside);
... and finally some housekeeping
// remove listener when destroying the widget
window.removeEventListener("click", onClickOutside);
Answered 2023-09-20 20:23:08
&& !$(event.target).parents("#foo").is("#foo")
inside the IF
statement so that any child elements won't close the menu when clicked. - anyone event.composedPath()
From: Event.composedPath()
The composedPath() method of the Event interface returns the event’s path, which is an array of the objects on which listeners will be invoked.
const target = document.querySelector('#myTarget')
document.addEventListener('click', (event) => {
const withinBoundaries = event.composedPath().includes(target)
if (withinBoundaries) {
target.innerText = 'Click happened inside element'
} else {
target.innerText = 'Click happened **OUTSIDE** element'
}
})
/* Just to make it good looking. You don't need this */
#myTarget {
margin: 50px auto;
width: 500px;
height: 500px;
background: gray;
border: 10px solid black;
}
<div id="myTarget">
Click me (or not!)
</div>
Answered 2023-09-20 20:23:08
if (el === event.target || el.contains(event.target))
... - anyone I have an application that works similarly to Eran's example, except I attach the click event to the body when I open the menu... Kinda like this:
$('#menucontainer').click(function(event) {
$('html').one('click',function() {
// Hide the menus
});
event.stopPropagation();
});
More information on jQuery's one()
function
Answered 2023-09-20 20:23:08
After research, I have found three working solutions
<script>
//The good thing about this solution is it doesn't stop event propagation.
var clickFlag = 0;
$('body').on('click', function () {
if(clickFlag == 0) {
console.log('hide element here');
/* Hide element here */
}
else {
clickFlag=0;
}
});
$('body').on('click','#testDiv', function (event) {
clickFlag = 1;
console.log('showed the element');
/* Show the element */
});
</script>
<script>
$('body').on('click', function(e) {
if($(e.target).closest('#testDiv').length == 0) {
/* Hide dropdown here */
}
});
</script>
<script>
var specifiedElement = document.getElementById('testDiv');
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
console.log('You clicked inside')
}
else {
console.log('You clicked outside')
}
});
</script>
Answered 2023-09-20 20:23:08
$("#menuscontainer").click(function() {
$(this).focus();
});
$("#menuscontainer").blur(function(){
$(this).hide();
});
Works for me just fine.
Answered 2023-09-20 20:23:08
Now there is a plugin for that: outside events (blog post)
The following happens when a clickoutside handler (WLOG) is bound to an element:
So no events are stopped from propagation and additional click handlers may be used "above" the element with the outside-handler.
Answered 2023-09-20 20:23:08
This worked for me perfectly!!
$('html').click(function (e) {
if (e.target.id == 'YOUR-DIV-ID') {
//do something
} else {
//do something
}
});
Answered 2023-09-20 20:23:08
I don't think what you really need is to close the menu when the user clicks outside; what you need is for the menu to close when the user clicks anywhere at all on the page. If you click on the menu, or off the menu it should close right?
Finding no satisfactory answers above prompted me to write this blog post the other day. For the more pedantic, there are a number of gotchas to take note of:
body { margin-left:auto; margin-right: auto; width:960px;}
Answered 2023-09-20 20:23:08
As another poster said there are a lot of gotchas, especially if the element you are displaying (in this case a menu) has interactive elements. I've found the following method to be fairly robust:
$('#menuscontainer').click(function(event) {
//your code that shows the menus fully
//now set up an event listener so that clicking anywhere outside will close the menu
$('html').click(function(event) {
//check up the tree of the click target to check whether user has clicked outside of menu
if ($(event.target).parents('#menuscontainer').length==0) {
// your code to hide menu
//this event listener has done its job so we can unbind it.
$(this).unbind(event);
}
})
});
Answered 2023-09-20 20:23:08
A simple solution for the situation is:
$(document).mouseup(function (e)
{
var container = $("YOUR SELECTOR"); // Give you class or ID
if (!container.is(e.target) && // If the target of the click is not the desired div or section
container.has(e.target).length === 0) // ... nor a descendant-child of the container
{
container.hide();
}
});
The above script will hide the div
if outside of the div
click event is triggered.
Answered 2023-09-20 20:23:08
Check the window click event target (it should propagate to the window, as long as it's not captured anywhere else), and ensure that it's not any of the menu elements. If it's not, then you're outside your menu.
Or check the position of the click, and see if it's contained within the menu area.
Answered 2023-09-20 20:23:08
There is also the focusout
event:
var button = document.getElementById('button');
button.addEventListener('click', function(e){
e.target.style.backgroundColor = 'green';
});
button.addEventListener('focusout', function(e){
e.target.style.backgroundColor = '';
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<button id="button">Click</button>
</body>
</html>
Answered 2023-09-20 20:23:08
Instead of using event.stopPropagation() which can have some side affects, just define a simple flag variable and add one if
condition. I tested this and worked properly without any side affects of stopPropagation:
var flag = "1";
$('#menucontainer').click(function(event){
flag = "0"; // flag 0 means click happened in the area where we should not do any action
});
$('html').click(function() {
if(flag != "0"){
// Hide the menus if visible
}
else {
flag = "1";
}
});
With just a simple if
condition:
$(document).on('click', function(event){
var container = $("#menucontainer");
if (!container.is(event.target) && // If the target of the click isn't the container...
container.has(event.target).length === 0) // ... nor a descendant of the container
{
// Do whatever you want to do when click is outside the element
}
});
Answered 2023-09-20 20:23:08
2020 solution using native JS API closest method.
document.addEventListener('click', ({ target }) => {
if (!target.closest('#menupop')) {
document.querySelector('#menupop').style.display = 'none'
}
})
#menupop {
width: 300px;
height: 300px;
background-color: red;
}
<div id="menupop">
clicking outside will close this
</div>
Answered 2023-09-20 20:23:08
I've had success with something like this:
var $menuscontainer = ...;
$('#trigger').click(function() {
$menuscontainer.show();
$('body').click(function(event) {
var $target = $(event.target);
if ($target.parents('#menuscontainer').length == 0) {
$menuscontainer.hide();
}
});
});
The logic is: when #menuscontainer
is shown, bind a click handler to the body that hides #menuscontainer
only if the target (of the click) isn't a child of it.
Answered 2023-09-20 20:23:08
focusout
for accessibilityThere is one answer here that says (quite correctly) that focusing on click
events is an accessibility problem since we want to cater for keyboard users. The focusout
event is the correct thing to use here, but it can be done much more simply than in the other answer (and in pure JavaScript too):
The 'problem' with using focusout
is that if an element inside your dialog/modal/menu loses focus, to something also 'inside', the event will still get fired. We can check that this isn't the case by looking at event.relatedTarget
(which tells us what element will have gained focus).
dialog = document.getElementById("dialogElement")
dialog.addEventListener("focusout", function (event) {
if (
// We are still inside the dialog so don't close
dialog.contains(event.relatedTarget) ||
// We have switched to another tab so probably don't want to close
!document.hasFocus()
) {
return;
}
dialog.close(); // Or whatever logic you want to use to close
});
There is one slight gotcha to the above, which is that relatedTarget
may be null
. This is fine if the user is clicking outside the dialog, but will be a problem if unless the user clicks inside the dialog and the dialog happens to not be focusable. To fix this you have to make sure to set tabIndex=0
so your dialog is focusable.
Answered 2023-09-20 20:23:08
The event has a property called event.path of the element which is a "static ordered list of all its ancestors in tree order". To check if an event originated from a specific DOM element or one of its children, just check the path for that specific DOM element. It can also be used to check multiple elements by logically OR
ing the element check in the some
function.
$("body").click(function() {
target = document.getElementById("main");
flag = event.path.some(function(el, i, arr) {
return (el == target)
})
if (flag) {
console.log("Inside")
} else {
console.log("Outside")
}
});
#main {
display: inline-block;
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
<ul>
<li>Test-Main</li>
<li>Test-Main</li>
<li>Test-Main</li>
<li>Test-Main</li>
<li>Test-Main</li>
</ul>
</div>
<div id="main2">
Outside Main
</div>
So for your case it should be
$("body").click(function() {
target = $("#menuscontainer")[0];
flag = event.path.some(function(el, i, arr) {
return (el == target)
});
if (!flag) {
// Hide the menus
}
});
Answered 2023-09-20 20:23:08
As a variant:
var $menu = $('#menucontainer');
$(document).on('click', function (e) {
// If element is opened and click target is outside it, hide it
if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) {
$menu.hide();
}
});
It has no problem with stopping event propagation and better supports multiple menus on the same page where clicking on a second menu while a first is open will leave the first open in the stopPropagation solution.
Answered 2023-09-20 20:23:08
I found this method in some jQuery calendar plugin.
function ClickOutsideCheck(e)
{
var el = e.target;
var popup = $('.popup:visible')[0];
if (popup==undefined)
return true;
while (true){
if (el == popup ) {
return true;
} else if (el == document) {
$(".popup").hide();
return false;
} else {
el = $(el).parent()[0];
}
}
};
$(document).bind('mousedown.popup', ClickOutsideCheck);
Answered 2023-09-20 20:23:08
Here is the vanilla JavaScript solution for future viewers.
Upon clicking any element within the document, if the clicked element's id is toggled, or the hidden element is not hidden and the hidden element does not contain the clicked element, toggle the element.
(function () {
"use strict";
var hidden = document.getElementById('hidden');
document.addEventListener('click', function (e) {
if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
}, false);
})();
(function () {
"use strict";
var hidden = document.getElementById('hidden');
document.addEventListener('click', function (e) {
if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
}, false);
})();
<a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a>
<div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>
If you are going to have multiple toggles on the same page you can use something like this:
hidden
to the collapsible item.(function () {
"use strict";
var hiddenItems = document.getElementsByClassName('hidden'), hidden;
document.addEventListener('click', function (e) {
for (var i = 0; hidden = hiddenItems[i]; i++) {
if (!hidden.contains(e.target) && hidden.style.display != 'none')
hidden.style.display = 'none';
}
if (e.target.getAttribute('data-toggle')) {
var toggle = document.querySelector(e.target.getAttribute('data-toggle'));
toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none';
}
}, false);
})();
<a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a>
<div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a>
<div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a>
<div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>
Answered 2023-09-20 20:23:08
Instead using flow interruption, blur/focus event or any other tricky technics, simply match event flow with element's kinship:
$(document).on("click.menu-outside", function(event){
// Test if target and it's parent aren't #menuscontainer
// That means the click event occur on other branch of document tree
if(!$(event.target).parents().andSelf().is("#menuscontainer")){
// Click outisde #menuscontainer
// Hide the menus (but test if menus aren't already hidden)
}
});
To remove click outside event listener, simply:
$(document).off("click.menu-outside");
Answered 2023-09-20 20:23:08
If you are scripting for IE and FF 3.* and you just want to know if the click occured within a certain box area, you could also use something like:
this.outsideElementClick = function(objEvent, objElement) {
var objCurrentElement = objEvent.target || objEvent.srcElement;
var blnInsideX = false;
var blnInsideY = false;
if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right)
blnInsideX = true;
if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom)
blnInsideY = true;
if (blnInsideX && blnInsideY)
return false;
else
return true;
}
Answered 2023-09-20 20:23:08
If someone is curious, here is a JavaScript solution (ES6):
window.addEventListener('mouseup', e => {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
// Or yourDiv.style.display = 'none';
}
})
And ES5, just in case:
window.addEventListener('mouseup', function (e) {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
yourDiv.classList.remove('show-menu');
// Or yourDiv.style.display = 'none';
}
});
Answered 2023-09-20 20:23:08
Use:
var go = false;
$(document).click(function(){
if(go){
$('#divID').hide();
go = false;
}
})
$("#divID").mouseover(function(){
go = false;
});
$("#divID").mouseout(function (){
go = true;
});
$("btnID").click( function(){
if($("#divID:visible").length==1)
$("#divID").hide(); // Toggle
$("#divID").show();
});
Answered 2023-09-20 20:23:08
Hook a click event listener on the document. Inside the event listener, you can look at the event object, in particular, the event.target to see what element was clicked:
$(document).click(function(e){
if ($(e.target).closest("#menuscontainer").length == 0) {
// .closest can help you determine if the element
// or one of its ancestors is #menuscontainer
console.log("hide");
}
});
Answered 2023-09-20 20:23:08
Here is a simple solution by pure javascript. It is up-to-date with ES6:
var isMenuClick = false;
var menu = document.getElementById('menuscontainer');
document.addEventListener('click',()=>{
if(!isMenuClick){
//Hide the menu here
}
//Reset isMenuClick
isMenuClick = false;
})
menu.addEventListener('click',()=>{
isMenuClick = true;
})
Answered 2023-09-20 20:23:08
() => {}
instead of function() {}
. What you have there is classified as plain JavaScript with a twist of ES6. - anyone I have used the below script done with jQuery.
jQuery(document).click(function(e) {
var target = e.target; // Target div recorded
if (!jQuery(target).is('#tobehide') ) {
jQuery(this).fadeOut(); // If the click element is not the above id, it will hide
}
})
Below find the HTML code:
<div class="main-container">
<div>Hello, I am the title</div>
<div class="tobehide">I will hide when you click outside of me</div>
</div>
You can read the tutorial here.
Answered 2023-09-20 20:23:08