Creating a series of adjacent dropdown menus with JavaScript, HTML, and CSS

I am encountering an issue while attempting to place multiple dropdown menus next to each other. I have included two categories as dropdown options in the header, but I am facing difficulty with one of them not functioning correctly. When I click on the non-working dropdown menu, nothing seems to happen.

let click = document.querySelector('.click');
let list = document.querySelector('.list');

click.addEventListener("click", () => {
  list.classList.toggle('newlist');
});
* {
  margin: 0;
  padding: 0;
  list-style: none;
  text-decoration: none;
}

.header {
  width: 100%;
  height: 100px;
  display: block;
  background-color: #F6D604;
  border-bottom: 3px solid black;
}

.header img {
  float: left;
  width: 180px;
  padding: 7px 20px;
  height: 80%;
  background: transparent;
}

img {
  image-rendering: auto;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}

.inner_header {
  width: 90%;
  height: 100%;
  display: block;
  margin: 0 auto;
}

.container {
  float: right;
  text-align: center;
  height: 100%;
  padding: 25px 5px;
  display: block;
  border-color: black;
}

.click {
  background-color: #F6D604;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-color: black;
  outline: none;
  width: 150px;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  border-radius: 10px;
}

.click:hover {
  background-color: #F6D604;
}

.links {
  border: none;
  outline: none;
  width: 150px;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-radius: 7px;
}

.list {
  position: absolute;
  transform: scaleY(0);
  transform-origin: top;
  transition: 0.3s;
  width: 150px;
  border-radius: 10px;
  border: 2px solid black;
  background-color: #fdfdfd;
}

.newlist {
  transform: scaleY(1);
  border-radius: 10px;
  border: 2px solid black;
}

.links {
  background-color: #fdfdfd;
  border-color: black;
}

.links:hover {
  background-color: #F6D604;
}
<div class="header">
  <div class="inner_header">
    <a href="../project/index.html">
      <div class="logo_container">
        <img src="assets/images/LOGO.png" alt="logo" />
      </div>
    </a>
    <div class="container">
      <button class="click">About</button>
      <div class="list">
        <button class="links">About us</button>
        <button class="links">Contact us</button>
      </div>
      <button class="click">Language</button>
      <div class="list">
        <button class="links">EN</button>
        <button class="links">NL</button>
      </div>
    </div>
  </div>
</div>

Answer №1

querySelector selects the first matching element, while querySelectorAll grabs all matching elements. To apply a listener, you must iterate through the elements. This approach ensures that any open navigation menus are closed when another is clicked. The use of the spread operator [...] facilitates iteration through elements. I introduced a new class navitem to properly display each submenu.

let click = document.querySelectorAll('.click');
let list = document.querySelectorAll('.list');
const showSub = (e) => {
    [...list].forEach(el => el.classList.remove('newlist')); // reset
    e.target.parentNode.querySelector('.list').classList.toggle('newlist');
    // alternatively
    //e.target.nextElementSibling.classList.toggle('newlist');
  }
  [...click].forEach(el => el.addEventListener("click", showSub));
* {
  margin: 0;
  padding: 0;
  list-style: none;
  text-decoration: none;
}

.header {
  width: 100%;
  height: 100px;
  display: block;
  background-color: #F6D604;
  border-bottom: 3px solid black;
}

.header img {
  float: left;
  width: 180px;
  padding: 7px 20px;
  height: 80%;
  background: transparent;
}

img {
  image-rendering: auto;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}

.inner_header {
  width: 90%;
  height: 100%;
  display: block;
  margin: 0 auto;
}

.container {
  float: right;
  text-align: center;
  height: 100%;
  padding: 25px 5px;
  display: block;
  border-color: black;
}

.click {
  background-color: #F6D604;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-color: black;
  outline: none;
  width: 150px;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  border-radius: 10px;
}

.navitem {
  width: 150px;
  display: inline-block;
}

.click:hover {
  background-color: #F6D604;
}

.links {
  border: none;
  outline: none;
  width: 150px;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-radius: 7px;
}

.list {
  position: absolute;
  transform: scaleY(0);
  transform-origin: top;
  transition: 0.3s;
  width: 150px;
  border-radius: 10px;
  border: 2px solid black;
  background-color: #fdfdfd;
}

.newlist {
  transform: scaleY(1);
  border-radius: 10px;
  border: 2px solid black;
}

.links {
  background-color: #fdfdfd;
  border-color: black;
}

.links:hover {
  background-color: #F6D604;
}
<div class="header">
  <div class="inner_header">
    <a href="../project/index.html">
      <div class="logo_container">
        <img src="assets/images/LOGO.png" alt="logo" />
      </div>
    </a>
    <div class="container">
      <div class='navitem'>
        <button class="click">About</button>
        <div class="list">
          <button class="links">About us</button>
          <button class="links">Contact us</button>
        </div>
      </div>
      <div class='navitem'>
        <button class="click">Language</button>
        <div class="list">
          <button class="links">EN</button>
          <button class="links">NL</button>
        </div>
      </div>
    </div>
  </div>
</div>

Answer №2

One important aspect of the querySelector method is that it retrieves the first matching DOM element. In your scenario, if you are using the same click class for multiple buttons, the event listener will only be attached to the first button. You can refer to the relevant documentation for more information (specifically the return value section).

To address this issue, I recommend either assigning unique classes to each button and attaching listeners individually, or selecting both buttons with a code snippet like the following:

let clicks = document.querySelectorAll('.click');

for (let click of clicks) {
  click.addEventListener("click",()=>{
    list.classList.toggle('newlist');
  });
}

Answer №3

To handle each button-list pair, use a forEach.

The JavaScript code below should help resolve your issues with JavaScript. Modify the CSS as necessary (I made some changes to the original HTML).

let drops = document.querySelectorAll('.drop');

drops.forEach(function(drop) {
  let click = drop.querySelector('.click');
  let list = drop.querySelector('.list');
  click.addEventListener("click", () => {
    list.classList.toggle('newlist');
  });
});
* {
  margin: 0;
  padding: 0;
  list-style: none;
  text-decoration: none;
}

.header {
  width: 100%;
  height: 100px;
  display: block;
  background-color: #F6D604;
  border-bottom: 3px solid black;
}

.header img {
  float: left;
  width: 180px;
  padding: 7px 20px;
  height: 80%;
  background: transparent;
}

img {
  image-rendering: auto;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}

.inner_header {
  width: 90%;
  height: 100%;
  display: block;
  margin: 0 auto;
}

.container {
  text-align: center;
  height: 100%;
  padding: 25px 5px;
  display: block;
  border-color: black;
}

.drop {
  width: 150px;
  float: right;
  padding: 0 5px;
}

.click {
  background-color: #F6D604;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-color: black;
  outline: none;
  width: 100%;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  border-radius: 10px;
}

.click:hover {
  background-color: #F6D604;
}

.links {
  border: none;
  outline: none;
  width: 150px;
  color: rgb(0, 0, 0);
  transition: 0.3s;
  padding: 12px;
  font-size: 1.2em;
  font-family: sans-serif;
  border-radius: 7px;

.list {
  position: absolute;
  transform: scaleY(0);
  margin-top: 1px;
  transform-origin: top;
  transition: 0.3s;
  width: 150px;
  border-radius: 10px;
  border: 2px solid black;
  background-color: #fdfdfd;
}

.newlist {
  transform: scaleY(1);
  border-radius: 10px;
  border: 2px solid black;
}

.links {
  background-color: #fdfdfd;
  border-color: black;
}

.links:hover {
  background-color: #F6D604;
}
<div class="header">
  <div class="inner_header">
    <a href="../project/index.html">
      <div class="logo_container">
        <img src="assets/images/LOGO.png" alt="logo" />
      </div>
    </a>
    <div class="container">
      <div class="drop">
        <button class="click">Language</button>
        <div class="list">
          <button class="links">EN</button>
          <button class="links">NL</button>
        </div>
      </div>
      <div class="drop">
        <button class="click">About</button>
        <div class="list">
          <button class="links">About us</button>
          <button class="links">Contact us</button>
        </div>
      </div>
    </div>
  </div>
</div>

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

"Error: The chai testing method appears to be improperly defined and is not

I am trying to set up a Mocha and Chai test. Here is my class, myClass.js: export default class Myclass { constructor() {} sayhello() { return 'hello'; }; } Along with a test file, test.myclass.js: I am attempting to a ...

Enhancing Image Quality upon Hovering

Is there a way to prevent the content of the article from moving when an image becomes absolutely positioned? The issue I am facing is that the image overlaps its container with overflow: hidden only when the img is absolute positioned. article { back ...

Ways to extend the length/size of the HTML5 range input type

Is there a way to adjust the length or size of the HTML5 range input for it to appear longer or bigger? <!DOCTYPE html> <html> <body> <form action="/" method="get"> Points: <input type="range" name="points" min="0" max="10"& ...

Differences between ClosureFeedbackCellArray and FeedbackVector in the V8 engine

Can you explain the distinction between ClosureFeedbackCellArray and FeedbackVector within V8? What steps are necessary to initiate the shift from ClosureFeedbackCellArray to FeedbackVector? What is the significance of the InterruptBudget attribute found ...

Button Triggering Javascript

Looking for a handy solution that allows users to either accept or reject a website's cookie policy. I came across an interesting library called cookies-EU-Banner (found at ) which seems to be quite popular. It recognizes when the user clicks on Reje ...

I must update the menu to show only one sub-menu at a time, ensuring that multiple menus cannot be displayed simultaneously

When I click on a menu option, it displays correctly, but when I click on another option, both are displayed. The goal is to only display one at a time. https://i.sstatic.net/J6vLf.png $('.sub-menu ul').hide(); $(".sub-menu a").click( ...

Preventing jQuery plugin from overriding default settings

I have created a jQuery plugin using the nested namespace pattern, inspired by the design template found in Addy Osmani's book. The plugin is a simple gallery and everything seems to be functioning correctly. However, I am facing an issue when attemp ...

Exploring collapsible data tables in Angular with Bootstrap styling

I am attempting to transform my static bootstrap data table, which displays the total count of fruits harvested in various months in an incremental manner, into a dynamic one using the JSON provided below: JSON { "fruit": [ { "fruitName": "Al ...

Invoke a Python function from JavaScript

As I ask this question, I acknowledge that it may have been asked many times before. If I missed the answers due to my ignorance, I apologize. I have a hosting plan that restricts me from installing Django, which provided a convenient way to set up a REST ...

PHP column number not found

Seeking assistance with a puzzling situation I encountered. My website features a form for administrators to submit user information, including links. The challenge lies in the uncertainty of how many links will be submitted - it could range from 5 to 35. ...

Achieving vertical alignment and stretching of subchild within a flexbox element

I am in the process of creating a mobile navigation menu using Flexbox. It will be a vertical menu that occupies 100% of the available height, with the navigation items evenly spaced and taking up the entire height. The structure I am using is ul>li> ...

The icon displays correctly in Firefox but is not visible in IE

link REL="SHORTCUT ICON" HREF="/images/greenTheme/favicon.ico" type="image/x-icon" While this code functions properly in Firefox, it appears to be causing issues in Internet Explorer. Can anyone provide guidance on how to resolve the compatibility issue w ...

"Unlocking the secret to fetching the id of the clicked element within a Highchart context menu

Is it possible to retrieve the id of a clicked button on the highchart context menu? Alternatively, is there a way to execute the click function twice? const contextButtonArray = []; contextButtonArray.push({ { text: 'TEST BUTTON&ap ...

attempting to communicate with Postman but encountering an error in the process

Upon attempting to send a request through Postman, I encountered an error. Nodemon is operational and the server is active in the terminal. index.server.js file //jshint esversion:6 const express = require("express"); const env = require("d ...

Issues with Node JS app's handling of php mailer code

I've made a basic website using the Node JS framework and included a php mailer for handling the contact form. Unfortunately, I'm facing issues getting it to function properly. Could it be possible that there is an underlying problem with Node JS ...

Tips for Editing an HTML File

As a beginner in the world of coding, I am currently working on creating a quiz maker. My question is how can I use code to edit a file? For example, if a user inputs a question name, how can the code automatically update the corresponding question in th ...

Prevent lengthy headers from disrupting the flow of the list items

I've encountered an issue while working on a website that features a list of items. When the title, such as "roller blinds," spans across two lines, it disrupts the layout below. How can I prevent this from happening without compromising on having lon ...

Saving form data with a tinymce textarea, radio button, and checkbox to the database

My form contains multiple textarea fields, radio buttons, checkboxes, and a select input. Initially, I was able to submit the form using PHP without any issues. However, when I integrated TinyMCE with one of the textareas, I had to introduce JavaScript to ...

Remove padding in Twitter Bootstrap table cells

One of my current projects requires making a button that fills the entire width and height of the TD element. I have attempted setting the normal .btn-warning with -Xpx!important, but it did not produce the desired result. Here is what I currently have: ...

Proper method for executing a synchronous AJAX POST request and subsequently submitting a form

Currently, I have an ASP submit button in my code. <asp:button runat="server" Text="Submit" id="btnSubmitOrder" OnClientClick="return SubmitOrder()" /> The JavaScript function I'm using, SubmitOrder(), is designed to execute a POST request. De ...