Using JavaScript to close a menu when clicking outside of it

I am currently working on enhancing a menu with a basic functionality. The goal is to toggle the menu between showing and hiding when a button is clicked, managed by a CSS class using JavaScript.

However, I have encountered an issue when attempting to combine this feature with window.addEventListener to close the menu upon an outside click. For some reason, it doesn't seem to work as expected. Can anyone shed light on why this might be happening?

Below is the code snippet that illustrates the structure of the menu setup:

<div class="c-wrapper">
  <button type="button" class="c-btn"> Click Me</button>
  <ul class="c-navigation">
    <li><a href="#">Hi there</a></li>
    <li><a href="#">Hello</a></li>
    <li><a href="#">Hola</a></li>
    <li><a href="#">Konichiwa</a></li>
  </ul>
</div>

Your assistance in resolving this matter would be greatly appreciated. Thank you in advance.

.c-wrapper{
  position:relative;
}

.c-btn{
  background-color:royalblue;
  border:none;
  color:white;
  padding:0.5rem 2rem;
  cursor:pointer;
  outline:none;
}


.c-navigation{
  list-style:none;
  background-color:#ccc;
  position:absolute;
  margin:0;
  padding:0;
  display:none;


  li{
    margin-top:0.5rem;
  }

  a{
    text-decoration:none;
    color:black;
    padding:1.4rem;
  }
}


.is-active{
  display:block;
}

Lastly, here is the JavaScript code that is causing the issue:

var button = document.querySelector('.c-btn');

button.addEventListener('click', function(){
  document.querySelector('.c-navigation').classList.toggle('is-active');
});

window.addEventListener('mouseup', function(event){
  var menu = document.querySelector('.c-navigation');
  if(event.target != menu && event.target.parentNode != menu){
    menu.style.display='none';
  }
});

Answer №1

Here is a suggestion to improve your code:

// Select the menu element
var menu = document.getElementById('menu');

// Close the modal when user clicks outside of it
window.addEventListener('click', function(event) {
  if (event.target === menu) {
    menu.style.display = "none";
  }
})

It's recommended to avoid directly manipulating styles with JavaScript. Instead, consider adding a class to the menu element.

menu.classList.add('hidden');

Then define the styling for the .hidden class in your CSS file.

.hidden {
    display: none;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for updating the state in React once all the fetch requests inside a loop have been successfully completed

Currently, I am working on a React application where I am facing an issue with setState in my App. I want to set the state only after all the AJAX fetches have been resolved to prevent multiple unnecessary re-rendering. Here is what I have attempted so fa ...

Having trouble with PHP form not functioning correctly?

Is there a way to display the var_dump with the 'selected country' information? I am having trouble due to an issue with the $res (array) $id. <?php if(isset ($_POST['submit'])) { $id = $_POST['cata']; $api = new ...

What is the process for adding color to an Object3D Object in ThreeJs?

My project involves importing Objects from a file, and I want to be able to color them by clicking on them. After attempting the following code: let mat = (this.scene.children[4].getObjectByName(intersects[0].object.name) as THREE.Mesh).material.color.set ...

Warning: multiple selections have been made on the checkboxes

Currently, I am using FormData to submit data and trying to alert the values of checked checkboxes in my form. At the moment, I can only make it work for one checkbox. How can I alert the values of all checked checkboxes? var formData = new FormData(docu ...

The functionality of the combobox in Vuetify differs from that of an input field

I have implemented Vuetify and am using its combobox component for search functionality on my website. However, I have noticed that the text value in the combobox only gets added to the watcher when the mouse exits the field. This behavior is not ideal f ...

Enhance a disabled button by incorporating a ripple effect

I've got a button that toggles on and off depending on the required form fields. When it's enabled, clicking it activates a ripple effect. Now I'd like to have the ripple effect even when the button is disabled. I attempted something simila ...

The local storage is unavailable on Chrome Mobile due to null value being

My error reporting system is detecting issues with JS Web Storage failures specifically on Android devices using Chrome mobile. Interestingly, I have not been able to replicate this error on my own Android device. The error message that keeps popping up i ...

How to strategically break Bootstrap 5 button groups for different resolutions?

Is there a way to create a line break in a specific place within a button group on a certain screen size? I have a button group with 4 buttons in a row, and I would like to split it into two lines after the first button if there isn't enough space. ...

Submitting a JavaScript array to MongoDB using a React application: A guide to success!

As a beginner delving into the world of React and MongoDB, I'm encountering difficulties in establishing communication between the two technologies. Recently, I've been following a detailed tutorial on Medium that focuses on utilizing the Plaid A ...

The RouterView component seems to be malfunctioning within the Vue project

I recently started working on a vue-project where I created a Home page with a sideBar component and a routerView component. Here's a preview: https://i.sstatic.net/f51tdsZ6.png When clicking on any sidebar item, the router navigates to the corresp ...

What is the functionality of ngCloak?

<html ng-app> <body> <p ng-cloak>{{foo}}</p> </body> </html> My interpretation: The HTML page is displayed. Once the DOMContentLoaded event is triggered, Angular begins bootstrapping. During the compilation ph ...

Ways to verify the presence of a key within an array of objects

I'm on a mission to determine whether a specified key exists in an array of objects. If the key value is present, I need to return true; otherwise, false. I enter the key into a text box as input and then attempt to check if it exists in the array of ...

What is the reason for AngularJS not utilizing the most recently assigned value?

<html> <head> <title>Test</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="angul ...

The select2 option seems to be malfunctioning as it is not

I have implemented a dropdown using Select2. Although I am able to retrieve data from the backend and display it successfully in Select2, I'm facing an issue with certain data that contains multiple spaces between words. For example: Test&nbsp;& ...

Tips for efficiently showcasing array responses in Vue.js and Laravel

I am looking to showcase array data within a .vue file, but I am uncertain about the process. This is my attempt: <template> <div id="app"> <table class="table table-striped"> <thead> <tr> ...

What could be causing VueJs2 computed properties to not update?

Check out this updated grid example from the official examples. In my application, I need to reposition the sortOrders array. created: function () { var vm = this; this.columns.forEach(function (key) { vm.sortOrders[key] = 1 }) ...

Executing a jQuery AJAX request for a second time

Upon hitting the submit button for the first time, the codes work successfully. However, upon hitting the button for the second time with correct email and password values, nothing happens and the user cannot log in. I have identified that the issue lies w ...

Why does Res.send return an empty object when console.log indicates it is not empty?

I am currently facing a challenge while using the Google Sheets API with Express, as I have limited experience with JavaScript. My goal is to pass a JSON object from Express to React, but for some reason, when I send the object, it appears empty on the fro ...

Transferring an object from one inventory to another

I'm in the process of developing a task manager that enables users to add and remove tasks. I am also working on enabling the ability for users to transfer tasks from one list to another. The current code I have written doesn't seem to be functio ...

A helpful guide on using workbox to effectively cache all URLs that follow the /page/id pattern, where id is a

Looking at this code snippet from my nodejs server: router.get('/page/:id', async function (req, res, next) { var id = req.params.id; if ( typeof req.params.id === "number"){id = parseInt(id);} res.render('page.ejs' , { vara:a , va ...