The close menu button is not functioning properly when clicked outside the menu - the buttonevent.matches is not recognized as a

I am encountering an issue with the dropdown menu that is not closing when clicking outside of the menu button. Despite having faced this problem before, I can't seem to find a solution now. Any help would be greatly appreciated as I am uncertain why the code is not functioning properly and some clarification on the matter would be beneficial.

let btnn = document.getElementById("btn");
btnn.addEventListener('click', function() {
  let dropdown = document.getElementById('dropdown');
  dropdown.classList.toggle("visible");
})

window.onclick = function(event){
    if (!event.target.matches('#btn')) {
        let dropd = document.getElementById('dropdown');
        dropd.classList.remove("visible");
    } 
}
body {
    height: 100vh;
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

.logo {
    display: block;
    text-align: left;
    background: red;
    height: 10vh;
}

.logo #logo {
    display: inline;
    line-height: 10vh;
    font-size: 3em;
    margin-left: 0.8em;
    
}

button#btn {
    display: inline;
    float: right;
    margin-right: 2em;
    margin-top: 0;
    margin-bottom: 0;
    border: none;
    background-color: red;
    padding: 0;
}

nav {
    display: block;
    background-color: black;
    width: 100vw;
}

nav ul {
    display: none;
    list-style-type: none;
    margin: 0;
    padding-left: 0;
}

nav ul li {
    text-align: center; 
}

.link {
    display: block;
    color: white;
    font-size: 2.4em;
    background-color: blue;
    text-decoration: none;
    width: 100vw;
    height: 7vh;
    line-height: 7vh;
    border-bottom: 2px solid black;
    text-align: center;
}

.visible {
    display: block;
}

.fa-bars:before, .fa-navicon:before {
    content: "\f0c9";
    font-size: 50px;
    line-height: 10vh;
}

@media only screen and (min-width: 480px) { 
    
    .fa-bars:before, .fa-navicon:before {
        font-size: 35px;
    }

    /* #dropdown {
        display: block;
    } */

}
  
  @media only screen and (min-width: 600px) {

    .fa-bars:before, .fa-navicon:before {
        font-size: 30px;
    }
    
}
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width">
    <!-- <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> -->
    <script
  src="https://code.jquery.com/jquery-3.6.0.js"
  integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
  crossorigin="anonymous"></script>
    <script src="https://kit.fontawesome.com/36947df53d.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
  <div class="logo">
    <p id="logo">Logo</p>
    <button id="btn"><i class="fa-solid fa-bars"></i></button>
  </div>
   <nav>
     <ul id="dropdown">
       <li><a href="#" class="link">Link 1</a></li>
       <li><a href="#" class="link">Link 2</a></li>
       <li><a href="#" class="link">Link 3</a></li>
     </ul>
   </nav>
    <script src="script.js"></script>
  </body>
</html>

Answer №1

Allow me to optimize your JavaScript code for better performance and accuracy.

document.querySelector("body").addEventListener("click", function(event){  
  let dropd = document.querySelector('#dropdown');
  if (!event.target.parentNode.matches('#btn')) {    
    dropd.classList.remove("visible");
  } else {
    dropd.classList.toggle("visible");
  }
});

By restructuring the code in this manner, we can prevent any conflicts between button click events and window click events. By checking if the click target matches the button ID, we can perform the appropriate action accordingly.

*** The use of parentNode is to ensure that the click event is detected on the intended element. By logging the event, you can observe that clicks may register on inner elements such as icons within a button. Thus, checking the parent node helps determine the exact location of the click.

Answer №2

To implement this functionality, you can use the following JavaScript code snippet in your file:

let btn = document.getElementById('btn');
btn.addEventListener('click', function() {
  let dropdown = document.getElementById('dropdown');
  dropdown.classList.toggle('visible');
});

document.body.addEventListener('click', () => {
    let dropDown = document.getElementById('dropdown');
    dropDown.classList.remove('visible');
}, true);

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

Prevent TypeScript from generalizing string literals as types

I have a constant Object called STUDY_TAGS with specific properties const STUDY_TAGS ={ InstanceAvailability: { tag: "00080056", type: "optional", vr: "string" }, ModalitiesinStudy: { tag: "00080061", type: " ...

What is the best way to stop Quasar dropdown list from moving along with the page scroll?

I am facing an issue with my code while using Quasar (Vue 3.0). The code snippet in question is: <q-select filled v-model="model" :options="options" label="Filled" /> When the drop-down menu is open and I scroll the pag ...

The behavior of React Router varies between local development on localhost and deployment on Heroku

Currently in the process of constructing a React-based website, initiated with create-react-app and incorporating react-router-dom`. The setup is as follows: index.js import React from 'react'; import ReactDOM from 'react-dom'; impor ...

What is the best way to handle an ajax call while working with the main Vue instance?

I have a VueJS component that makes an AJAX call to GitHub using the following code: (Child) Component Vue.http.get('user/repos').then((response) => { console.log(response); }, (response) => { console.log(response); }); The issue ...

Transferring the AJAX response into a JavaScript variable

New to AJAX and JS here. I am implementing an AJAX code that fetches data from a php service. I am trying to figure out how to store the returned data in a JavaScript variable, which I can then display on the UI. Below is my AJAX code snippet: <script ...

Add numerous submit buttons within a form. Upon clicking on a button, the form should be submitted to a specific URL using AJAX

I have a form with two submit buttons: one labeled as "SUBMIT" and the other as "SCHEDULE NEXT ROUND". When a user clicks on the "SUBMIT" button, the form values should be stored in the database and redirect to the view page. If they click on the "SCHEDULE ...

Is there a way to escape from an iFrame but only for specific domains?

if (top.location != self.location) { top.location = self.location.href; } If my website is being displayed in an iFrame, this code will break out of it. But I want this to happen only for specific domains. How can I perform that check? ...

Enhance the functionality of selectize.js by incorporating select options through ajax

I'm currently working on implementing options to a select box using AJAX and selectize.js. When not using selectize.js, everything functions correctly. The two select boxes are interconnected so that when one is updated, the values in the other select ...

Retrieving the Vue component object while inside the FullCalendar object initialized within the component

When using Full Calendar with VueJS, I ran into a problem where I needed to open a custom modal when clicking on a time slot in the calendar. The issue was that I couldn't call a function outside of the Full Calendar object to handle this. This is bec ...

Is there a way to make a selected option stay selected in vue.js 2?

Here is the structure of my Vue component : <template> <select class="form-control" v-model="selected" :required @change="changeLocation"> <option :selected>Choose Province</option> <option v-for="option in o ...

What is the correct method for caching fonts within an Angular application?

In the process of developing a web application similar to photoshop-minis using Angular, one key aspect I am focusing on is reducing load times. Particularly when it comes to fonts, as not all necessary fonts are available through Google Fonts. Instead of ...

Aligning cards

Struggling to align these cards perfectly at center: Despite thorough research on both Google and Stack Overflow, the solution continues to elude me. I've experimented with various methods such as display: flex, justify-content: center, and align-ite ...

Create a list that starts with a header determined by an object's attribute within an array

Currently in Vue, I am attempting to create a list based on a specific property within an object. The array being retrieved from the vuex store is structured as follows: const array = [ { name: "British title string" nationality: "British" }, { ...

What is the best way to handle a specific submit button using jQuery/Ajax?

I created a web page with 4 submit buttons that all call the same PHP page process.php using jQuery/Ajax. I trigger this PHP page using the onClick event as shown below: <div class="col-md-12"> <input type="hidden" name="_token" value="<?p ...

What is the best way to apply a hover rule to a CSS class in order to change the color of a specific row when hovering in

I have managed to successfully apply a classname and add color to a specific row in my react-table. However, I am facing difficulty in adding a hover rule to this className to change the color when I hover over the row. Can someone guide me on how to apply ...

Selecting elements by their name using vanilla JavaScript

I am facing an issue where I have to assign a value to a checkbox based on certain variables. The challenge lies in the naming convention used in the HTML I am working with: <input id="jc_1" type="checkbox" name="jc[1]"> <input id="jc_2" type="c ...

My goal is to send distinct entries for each user that accesses the system from a MySQL database

As a beginner, I need help figuring out how to send each logged-in user a list of unique records from the database. I want to ensure that no duplicate records are sent to different users. How can I achieve this? Below is the code snippet responsible for ...

React and Express are incompatible due to the error message "TypeError: undefined is not a function

I am attempting to display the data from this array on my website using react and express: [{"LocationName":"LIBERTY DOGS","Address":"105 Greenwood Ave N, Seattle WA","Available":"Y"},{"LocationName":"FREEDOM DOGS","Address":"105 Greenwood Ave N, Seattle ...

Embed a Telegram account onto an HTML page using the <iframe> element

Is there a way to display the personal Telegram account in an iframe tag? I experimented with the code below, but unfortunately it did not produce the desired result: <iframe src="https://telegram.me/joinchat/BfNEij9CbDh03kwXacO5OA"></iframe> ...

Troubleshooting: Imported Variable in Angular 2+ Throwing Module Not Found Error

During my testing process, I encountered an issue when trying to require a .json file with data to perform checks on. Despite passing the string indicating where to find the file into the require function, it seems to be unsuccessful... Success: const da ...