Issue with HTML dropdown functionality

I’m facing an issue with my dropdown menu. Clicking on a button should toggle the dropdown menu, showing it if closed and hiding it if open. However, the dropdown menu does not close when I click the button again. I suspect the problem lies with the closeAll function, which is necessary to close another dropdown menu when the first one is open.

 /* Toggle between hiding and showing dropdown content when button is clicked */
    function myFunction() {
    closeAll();
        document.getElementById("myDropdown").classList.toggle("show");
       }

       function myFunction2() {
        closeAll();
        document.getElementById("myDropdown2").classList.toggle("show");
    }

    function closeAll(){
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
     var openDropdown = dropdowns[i];
      openDropdown.classList.remove('show');
    }
    }

    // Close dropdown menu when user clicks outside of it
    window.onclick = function(event) {
      if (!event.target.matches('.dropbtn')) {
        var dropdowns = document.getElementsByClassName("dropdown-content");
        var i;
        for (i = 0; i < dropdowns.length; i++) {
          var openDropdown = dropdowns[i];
          if (openDropdown.classList.contains('show')) {
            openDropdown.classList.remove('show');

          }
        }
      }
    }
/* Dropdown Button */
    .dropbtn {
    background-color: #4CAF50;
    color: white;
    padding: 16px;
    font-size: 16px;
    border: none;
    cursor: pointer;
    }

    /* Dropdown button on hover & focus */
    .dropbtn:hover, .dropbtn:focus {
        background-color: #3e8e41;
    }

    /* The container <div> - needed to position the dropdown content */
    .dropdown {
        position: relative;
        display: inline-block;
    }

    /* Dropdown Content (Hidden by Default) */
    .dropdown-content {
        display: none;
        position: absolute;
        background-color: #f9f9f9;
        min-width: 150px;
        box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
        z-index: 1;
    }

    /* Links inside the dropdown */
    .dropdown-content a {
        color: black;
        padding: 12px 16px;
        text-decoration: none;
        display: block;
    }

    /* Change color of dropdown links on hover */
    #myDropdown a:hover {background-color: #f1f1f1}

    /* Show the dropdown menu (use JS to add this class to the .dropdown-content 
    container when the user clicks on the dropdown button) */
    .show {display:block;}

    #myDropdown2{
    min-width:200px;
    border:4px solid red;

    }

    #myDropdown2 a:hover{
    color:red;
    }

    .left-bar{
    float:left;
    }

    .right-bar{
    float:left;
    }
    

    <div class="dropdown">
      <button onclick="myFunction()" class="dropbtn">Dropdown</button>
      <div id="myDropdown" class="dropdown-content">
        <a href="#">Link 1</a>
        <a href="#">Link 2</a>
        <a href="#">Link 3</a>
      </div>
    </div>

    <div class="dropdown">
      <button onclick="myFunction2()" class="dropbtn">Dropdown</button>
      <div id="myDropdown2" class="dropdown-content">
    <div class="left-bar">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
    </div>

    <div class="right-bar">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
    </div>
      </div>
    </div>

Answer №1

Your `myFunction()` and `myFunction2()` functions first close all dropdown menus using `closeAll();`, then the next line `document.getElementById("myDropdown").classList.toggle("show");` shows it again. So, when you click the button again, it does not close.

To fix it:

Simply remove the function `closeAll();` and change your code like this:

function myFunction() {
    document.getElementById("myDropdown2").classList.remove("show");
    document.getElementById("myDropdown").classList.toggle("show");
}

function myFunction2() {
    document.getElementById("myDropdown").classList.remove("show");
    document.getElementById("myDropdown2").classList.toggle("show");
}

Full code:

function myFunction() {
  document.getElementById("myDropdown2").classList.remove("show");
  document.getElementById("myDropdown").classList.toggle("show");
}

function myFunction2() {
  document.getElementById("myDropdown").classList.remove("show");
  document.getElementById("myDropdown2").classList.toggle("show");
}

// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');

      }
    }
  }
}
.dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

/* Dropdown button on hover & focus */
.dropbtn:hover,
.dropbtn:focus {
  background-color: #3e8e41;
}

/* The container <div> - needed to position the dropdown content */
.dropdown {
  position: relative;
  display: inline-block;
}

/* Dropdown Content (Hidden by Default) */
.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 150px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

/* Links inside the dropdown */
.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

/* Change color of dropdown links on hover */
#myDropdown a:hover {
  background-color: #f1f1f1
}

/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
.show {
  display: block;
}

#myDropdown2 {
  min-width: 200px;
  border: 4px solid red;
}

#myDropdown2 a:hover {
  color: red;
}

.left-bar {
  float: left;
}

.right-bar {
  float: left;
}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>

<div class="dropdown">
  <button onclick="myFunction2()" class="dropbtn">Dropdown</button>
  <div id="myDropdown2" class="dropdown-content">
    <div class="left-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>

    <div class="right-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
</div>

Answer №2

Eliminate the need for myFunction() and myFunction2(), as well as closeAll();

Instead, utilize ToggleClass

/* Handling click events on buttons to toggle dropdown visibility */
function myFunction() {
  
  document.getElementById("myDropdown").classList.toggle("show");
}

function myFunction2() {
  
  document.getElementById("myDropdown2").classList.toggle("show");
}

function closeAll() {
  var dropdowns = document.getElementsByClassName("dropdown-content");
  var i;
  for (i = 0; i < dropdowns.length; i++) {
    var openDropdown = dropdowns[i];
    openDropdown.classList.remove('show');
  }
}

// Close the dropdown when clicked outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
/* Styling for dropdown button */

.dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}


/* Hover and focus effects on dropdown button */

.dropbtn:hover,
.dropbtn:focus {
  background-color: #3e8e41;
}

/* Container div for positioning dropdown content */

.dropdown {
  position: relative;
  display: inline-block;
}

/* Styling for hidden dropdown content */

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 150px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

/* Styling for links inside dropdown */

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

/* Hover effect on dropdown links */

#myDropdown a:hover {
  background-color: #f1f1f1
}

/* Display the dropdown menu */

.show {
  display: block;
}

#myDropdown2 {
  min-width: 200px;
  border: 4px solid red;
}

#myDropdown2 a:hover {
  color: red;
}

.left-bar {
  float: left;
}

.right-bar {
  float: left;
}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>

<div class="dropdown">
  <button onclick="myFunction2()" class="dropbtn">Dropdown</button>
  <div id="myDropdown2" class="dropdown-content">
    <div class="left-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>

    <div class="right-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
</div>

Answer №3

One issue arises when you execute the function closeAll() and then proceed to toggle the dropdown which was initially clicked by the user, causing it to open again.

To address this problem, it is essential to check if the current dropdown is already open before trying to open it again.

/* Upon clicking the button, toggle between displaying and hiding the dropdown content */
function myFunction() {
  var isOpen = document.getElementById("myDropdown").classList.contains("show");
  closeAll();
  if (!isOpen) {
    document.getElementById("myDropdown").classList.add("show");
  }
}

function myFunction2() {
  var isOpen = document.getElementById("myDropdown2").classList.contains("show");
  closeAll();
  if (!isOpen) {
    document.getElementById("myDropdown2").classList.toggle("show");
  }
}

function closeAll() {
  var dropdowns = document.getElementsByClassName("dropdown-content");
  var i;
  for (i = 0; i < dropdowns.length; i++) {
    var openDropdown = dropdowns[i];
    openDropdown.classList.remove('show');
  }
}

// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');

      }
    }
  }
}
/* Dropdown Button */

.dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}


/* Dropdown button on hover & focus */

.dropbtn:hover,
.dropbtn:focus {
  background-color: #3e8e41;
}


/* The container <div> - needed to position the dropdown content */

.dropdown {
  position: relative;
  display: inline-block;
}


/* Dropdown Content (Hidden by Default) */

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 150px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}


/* Links inside the dropdown */

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}


/* Change color of dropdown links on hover */

#myDropdown a:hover {
  background-color: #f1f1f1
}


/* Show the dropdown menu (use JS to add this class to the .dropdown-content 
    container when the user clicks on the dropdown button) */

.show {
  display: block;
}

#myDropdown2 {
  min-width: 200px;
  border: 4px solid red;
}

#myDropdown2 a:hover {
  color: red;
}

.left-bar {
  float: left;
}

.right-bar {
  float: left;
}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>

<div class="dropdown">
  <button onclick="myFunction2()" class="dropbtn">Dropdown</button>
  <div id="myDropdown2" class="dropdown-content">
    <div class="left-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>

    <div class="right-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
</div>

Answer №4

Here's a suggestion: try removing the class show from another dropdown when the dropdown with the class show is clicked. This ensures that only the clicked dropdown will have its show class removed, preventing the toggling event on other dropdowns as well.

Array.prototype.indexOf.call(document.getElementById("myDropdown").classList, 'show')

This code is used to check for the existence of the show class.

/* Define toggle functionality for dropdowns */

function myFunction() {
  if(Array.prototype.indexOf.call(document.getElementById("myDropdown").classList, 'show')){
    document.getElementById("myDropdown").classList.toggle("show");
    document.getElementById("myDropdown2").classList.remove("show");
  } else {
    closeAll();
  }
}

function myFunction2() {
  if(Array.prototype.indexOf.call(document.getElementById("myDropdown2").classList, 'show')){
    document.getElementById("myDropdown2").classList.toggle("show");
    document.getElementById("myDropdown").classList.remove("show");
  } else {
    closeAll();
  }
}

function closeAll() {
  var dropdowns = document.getElementsByClassName("dropdown-content");
  var i;
  for (i = 0; i < dropdowns.length; i++) {
    var openDropdown = dropdowns[i];
    openDropdown.classList.remove('show');
  }
}

// Close the dropdown menu if the user clicks outside of it

window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
/* Dropdown Button */

.dropbtn {
  background-color: #4CAF50;
  color: white;
  padding: 16px;
  font-size: 16px;
  border: none;
  cursor: pointer;
}

/* Dropdown button on hover & focus */

.dropbtn:hover,
.dropbtn:focus {
  background-color: #3e8e41;
}

/* The container <div> - needed to position the dropdown content */

.dropdown {
  position: relative;
  display: inline-block;
}

/* Dropdown Content (Hidden by Default) */

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f9f9f9;
  min-width: 150px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 1;
}

/* Links inside the dropdown */

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

/* Change color of dropdown links on hover */

#myDropdown a:hover {
  background-color: #f1f1f1
}

/* Show the dropdown menu (use JS to add this class to the .dropdown-content 
    container when the user clicks on the dropdown button) */

.show {
  display: block;
}

#myDropdown2 {
  min-width: 200px;
  border: 4px solid red;
}

#myDropdown2 a:hover {
  color: red;
}

.left-bar {
  float: left;
}

.right-bar {
  float: left;
}
<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Dropdown</button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>

<div class="dropdown">
  <button onclick="myFunction2()" class="dropbtn">Dropdown</button>
  <div id="myDropdown2" class="dropdown-content">
    <div class="left-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>

    <div class="right-bar">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div>
</div>

Answer №5

To begin, close all dropdowns and then toggle the current one, causing it to reopen. To modify this behavior, adjust the closeAll() function to accept a parameter representing the current dropdown or button, closing all others except for this one.

closeAll(currentDropdown){
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
        var openDropdown = dropdowns[i];
        if(openDropdown != currentDropdown){
            openDropdown.classList.remove('show');
        }
    }
}

You can store the desired states of elements in an array and apply these states each time one is clicked.

// executed once on page load
var dropdowns = new array();
var tmpdropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < tmpdropdowns.length; i++) {
    dropdowns[tmpdropdowns[i].id] = 0;
}


// executed on click of one button
for (i = 0; i < dropdowns.length; i++) {
    dropdowns[i] = 0;
}
dropdowns[/*clicked id*/] = (dropdowns[/*clicked id*/] + 1) % 2;
for (var key in dropdowns) {
   if(dropdowns[key] == 0) {
       document.getElementById[key].classList.remove("show");
   } else {
       document.getElementById[key].classList.add("show");
   }
}

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

Having difficulty displaying Laravel API data with Relationship in Vue Js

Working on a project that involves Laravel 10 API and Vue.js 3 frontend In my EmployeeController.php file, I have three models: Employee, Title, and Salary. The Employee model has a many-to-many relationship with the Salary and Title models, while the Sal ...

What is the best way to transfer information from node.js to HTML?

This is a sample code in Node.js var http = require('http'); var request = require("request"); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('Hello World!& ...

ES6 does not work with React hello world

Can anyone help me with troubleshooting my code? I've checked the console on jsbin and can't find any errors. http://jsbin.com/susumidode/edit?js,console,output Class secondComponenent extends React.Component { render(){ return ( &l ...

Is there a way to prevent HTML Tidy from inserting newlines before closing tags?

Have you ever noticed how HTML Tidy always seems to add an extra newline before the closing tag? It's so frustrating! For instance: <p>Some text</p> ends up looking like this: <p>Some text </p> Is there a way to make Tidy k ...

How to keep jQuery horizontal submenu open when clicking on the menu

Seeking assistance with a menu issue. I have a horizontal menu with subitems that display when clicked, but having trouble with the submenu behavior. When clicking on a submenu item, I want it to remain open and show the related items underneath it. For ex ...

Clicking on the element will not cause the body to scroll

For some reason, I need to keep the onclick function, but I'm struggling to make it work as intended. What I want is for the body to slide to the next logo when the previous logo is clicked. This is a simplified version of what I have: <div class ...

resizing videos in wordpress

Similar Question: How to Resize Embedded Videos Using PHP I am looking to adjust the dimensions of videos to be 280 pixels in height and 520 pixels in width on my WordPress homepage. Currently, the code is using the original YouTube dimensions: ...

There is an issue with Node/Express not accurately updating the data model

I recently went through a tutorial on creating a RESTful API with Node.js and MongoDB. While it worked well overall, I encountered a few issues. My Player model is as follows: var player = new mongoose.Schema({ name: String, email: String, score: String } ...

Retrieve the element that triggered the event listener within Nuxt

I am currently developing a Nuxt project where I have set up my component using the code below. The select-parent-container has a click event attached to it. Whenever this event is triggered, I need to identify and return the specific parent container that ...

A tutorial on how to switch out a font-awesome icon simply by clicking on it - collapsible content

I have some HTML code with a script for my website that allows text to be collapsed or expanded by clicking on a font awesome arrow. I am looking to have an arrow that points up when clicked to collapse the text and points down when clicked to expand the t ...

In React production, the use of .map as a function is unavailable

While my express react app build runs smoothly locally with the map function, the transition to production triggers an error stating that 'map' is not a function. The error specifically points to the line declaring 'let returnlist'. Be ...

What are the consequences of including incorrect attributes in HTML tags?

It has come to my attention that the browser remains silent when I use non-existent attribute names for HTML tags. For example: <!DOCTYPE html> <html> <head test1="abc"> <title test2="cba">My Sample Project</title> ...

What is causing the lack of response in the select box on Mac Chrome when I try to click on it?

Similar Question: JQuery function doesn't work on Chrome on Mac, but works on Chrome on Win 7 and all other browsers I am encountering an issue with a select-option list <div class="social-option"> <select name="hex_theme_options[soc ...

Tips for repeatedly clicking a button over 50 times using Protractor

Is it possible to click the same button more than 50 times using a loop statement in Protractor? And will Protractor allow this action? Below is my locator : var nudge= element(by.xpath("//a[@class='isd-flat-icons fi-down']")); nudge.click(); ...

Efficient methods to reach the desired result using Selenium WebDriver promises

After working on a piece of code that utilizes Selenium WebDriver to retrieve the text of an element, I am wondering if there is a more concise way to accomplish this task? async function getText(driver, locator) { return await (await driver.findEleme ...

Reference now inactive in an array object no longer exhibiting reactivity

After implementing the following code successfully, we noticed that changing the language updates the text correctly thanks to the ref: const mainNavigationLinks = computed(() => [ { label: context.root.$t('navigationMenu.home') }, { labe ...

How can I pass a value from a jQuery variable to a PHP variable?

Utilizing jQuery to create a table based on the output of JSON. The JSON values are retrieved from a SoapClient, which is functioning correctly and producing the desired output. https://i.sstatic.net/vJbfW.png Now, the goal is to assign the value of the ...

What could be causing the issue with Vite build and npm serve not functioning together?

After shifting from CRA to VITE, I am encountering a problem with serving my app. I successfully build my app using vite build. and can serve it using Vite serve without any issues. However, I want to use npm's serve command. Whenever I run vite bui ...

What is the best way to horizontally replace buttons in a Navbar?

I'm currently new to coding and I'm attempting to create a navbar using Bootstrap. However, I'm struggling to align the buttons horizontally. I've attempted using class="float-right" on every element without success. I even tried using ...

Having trouble with displaying the CSS background image?

I've been attempting to configure background images using CSS, but for some reason, I'm not able to get the images to show up correctly. Below is the CSS code that I'm working with: a.fb { background-image: url('img/Facebook.png&a ...