Nested lists with consistent height regardless of the quantity of items

I am currently working on a dropdown multicolumn menu that contains nested lists. My goal is to ensure that all three lists (or columns) have the same height, even if they contain a different number of items. Since the lists are dynamic and the number of items can vary, I am wondering if it is possible to achieve this without having to rewrite the HTML code. The image linked below illustrates what I am trying to accomplish:

https://i.sstatic.net/Kigu7.png

const firstlevel = document.querySelectorAll(".first-level > li");
const secondlevel = document.querySelectorAll(".second-level > li");

const menuButton = document.querySelector(".menu-button")

menuButton.addEventListener("click", (e) => {
  menuButton.classList.add('active');
});

firstlevel.forEach((item) => {
  item.addEventListener("click", (e) => {
    firstlevel.forEach((elem) => {
      elem.classList.remove("active");
    });

    item.classList.add("active");

    item.querySelector('ul > li').classList.add("active");

  });
});

secondlevel.forEach((item) => {
  item.addEventListener("click", (e) => {

    secondlevel.forEach((elem) => {
      elem.classList.remove("active");
    });
    item.classList.add("active");
  });
});
*,
*::before,
*::after {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
}

body {
  font-family: sans-serif;
  margin: 0;
  padding: 10px;
}

.dropdown {
  margin: 0;
  padding: 0;
  list-style: none;
  width: 100px;
  background-color: #0abf53;
}

.dropdown li {}

.dropdown li a {
  color: #ffffff;
  text-align: center;
  text-decoration: none;
  display: block;
  padding: 10px;
}

.dropdown li ul {
  position: absolute;
  margin: 0;
  padding: 0;
  list-style: none;
  display: none;
  line-height: normal;
  background-color: #333;
}

.dropdown li ul li a {
  text-align: left;
  color: #cccccc;
  font-size: 14px;
  padding: 10px;
  display: block;
  white-space: nowrap;
}

.dropdown li ul li a:hover {
  background-color: #0abf53;
  color: #ffffff;
}

.dropdown li ul li ul {
  left: 100%;
  top: 0;
}
  
ul li:hover>a {
  background-color: #0abf53;
  color: #ffffff !important;
}

ul li.active>ul {
  display: block;
}
<ul class="dropdown">
  <li class="menu-button"><a href="#">Menu</a>
    <ul class="first-level">
      <li class="active"><a href="#">1</a>
        <ul class="second-level">
          <li class="active"><a href="#">1-1</a>
            <ul>
              <li><a href="">1-1-1</a></li>
              <li><a href="">1-1-2</a></li>
              <li><a href="">1-1-3</a></li>
            </ul>

          </li>
          <li><a href="#">1-2</a>
            <ul>
              <li><a href="">1-2-1</a></li>
              <li><a href="">1-2-2</a></li>
              <li><a href="">1-2-3</a></li>
            </ul>
          </li>
          <li><a href="#">1-3</a>
            <ul>
              <li><a href="">1-3-1</a></li>
              <li><a href="">1-3-2</a></li>
              <li><a href="">1-3-3</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a href="#">2</a>
        <ul class="second-level">
          <li><a href="#">2-1</a>
            <ul>
              <li><a href="">2-1-3</a></li>
              <li><a href="">2-1-3</a></li>
              <li><a href="">2-1-3</a></li>
            </ul>
          </li>
          <li><a href="#">2-2</a>
            <ul>
              <li><a href="">2-2-3</a></li>
              <li><a href="">2-2-3</a></li>
              <li><a href="">2-2-3</a></li>
            </ul>
          </li>
          <li><a href="#">2-3</a>
            <ul>
              <li><a href="">2-3-1</a></li>
              <li><a href="">2-3-2</a></li>
              <li><a href="">2-3-3</a></li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

This is my current attempt: https://codepen.io/Agrimensor/pen/vYgGJwr

Answer №1

One simple solution could be to send a value from JavaScript to CSS for calculating the height.

const listLength = () => {
  let container = document.querySelector('.dropdown');
  let items = 0;
  let lists = container.querySelectorAll(".class-name-to-select-ul")
  list.forEach(x => {
    let liCount = x.querySelectorAll("li").lenght;
    items = items > liCount ? items : liCount;
  });
  container.setAttribute('style', `--items:${items}`)
}
ul {
  height: calc(var(--items) * var(--item-height))
}

Answer №2

Adjust the height of .dropdown ul by adding the following CSS:

.dropdown ul {
  height: 110px;
}

const firstlevel = document.querySelectorAll(".first-level > li");
const secondlevel = document.querySelectorAll(".second-level > li");

const menuButton = document.querySelector(".menu-button")

menuButton.addEventListener("click", (e) => {
  menuButton.classList.add('active');
});

firstlevel.forEach((item) => {
  item.addEventListener("click", (e) => {
    firstlevel.forEach((elem) => {
      elem.classList.remove("active");
    });

    item.classList.add("active");

    item.querySelector('ul > li').classList.add("active");

  });
});

secondlevel.forEach((item) => {
  item.addEventListener("click", (e) => {

    secondlevel.forEach((elem) => {
      elem.classList.remove("active");
    });
    item.classList.add("active");
  });
});
*,
*::before,
*::after {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
}

body {
  font-family: sans-serif;
  margin: 0;
  padding: 10px;
}

.dropdown {
  margin: 0;
  padding: 0;
  list-style: none;
  width: 100px;
  background-color: #0abf53;
}

.dropdown li {}

.dropdown li a {
  color: #ffffff;
  text-align: center;
  text-decoration: none;
  display: block;
  padding: 10px;
}

.dropdown li ul {
  position: absolute;
  margin: 0;
  padding: 0;
  list-style: none;
  display: none;
  line-height: normal;
  background-color: #333;
}

.dropdown li ul li a {
  text-align: left;
  color: #cccccc;
  font-size: 14px;
  padding: 10px;
  display: block;
  white-space: nowrap;
}

.dropdown li ul li a:hover {
  background-color: #0abf53;
  color: #ffffff;
}

.dropdown li ul li ul {
  left: 100%;
  top: 0;
}

ul li:hover>a {
  background-color: #0abf53;
  color: #ffffff !important;
}

ul li.active>ul {
  display: block;
}


/*👇👇 NEW 👇👇*/

.dropdown ul {
  height: 110px;
}
<ul class="dropdown">
  <li class="menu-button"><a href="#">Menu</a>
    <ul class="first-level">
      <li class="active"><a href="#">1</a>
        <ul class="second-level">
          <li class="active"><a href="#">1-1</a>
            <ul>
              <li><a href="">1-1-1</a></li>
              <li><a href="">1-1-2</a></li>
              <li><a href="">1-1-3</a></li>
            </ul>

          </li>
          <li><a href="#">1-2</a>
            <ul>
              <li><a href="">1-2-1</a></li>
              <li><a href="">1-2-2</a></li>
              <li><a href="">1-2-3</a></li>
            </ul>
          </li>
          <li><a href="#">1-3</a>
            <ul>
              <li><a href="">1-3-1</a></li>
              <li><a href="">1-3-2</a></li>
              <li><a href="">1-3-3</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a href="#">2</a>
        <ul class="second-level">
          <li><a href="#">2-1</a>
            <ul>
              <li><a href="">2-1-3</a></li>
              <li><a href="">2-1-3</a></li>
              <li><a href="">2-1-3</a></li>
            </ul>
          </li>
          <li><a href="#">2-2</a>
            <ul>
              <li><a href="">2-2-3</a></li>
              <li><a href="">2-2-3</a></li>
              <li><a href="">2-2-3</a></li>
            </ul>
          </li>
          <li><a href="#">2-3</a>
            <ul>
              <li><a href="">2-3-1</a></li>
              <li><a href="">2-3-2</a></li>
              <li><a href="">2-3-3</a></li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

👉 See it live on Codepen

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

Guide to creating a visual representation of an audio stream in HTML5

Is it possible to draw a waveform of audio extracted from a webcam media stream in real-time using HTML5 and JavaScript? I have explored: https://github.com/soundcloud/waveformjs https://github.com/katspaugh/wavesurfer.js However, these solutions appea ...

The issue is with the function t.split in Jquery mobile, it seems to

Currently, I am in the process of developing a website that pulls content dynamically from a database and inserts it into the HTML code. The site is designed with JQuery Mobile pages to allow for smooth transitions when clicking on links. Despite using JQ ...

Eliminate redundant items within an array, focusing on a single attribute in the objects

Recently, I was tackling a coding challenge involving identifying unique objects within an array. After researching and experimenting with various code snippets, I managed to find a solution that almost fits my requirements. Let's consider the follo ...

Learn how to use onclick event in an anchor tag to send post values through Ajax!

Can I send post values via AJAX using an onclick event on an anchor tag? I've tried the following code but I'm not receiving any post values. How can I make it work? ............................................................................. ...

Is there a way to utilize the passValue function twice within Javascript?

Is there a way to display the value of an input field in multiple spots throughout the code? Currently, my code only passes it once. How can I rewrite it to show up again later in the code? //HTML: <input type="text" name="amount" onchange="passValue ...

Receiving NaN in javascript when attempting to calculate the sum using a text input field

I am trying to calculate the total value by adding a fixed price with another value entered in a text input field. Here is the HTML code snippet: <%= f.text_field :hoursclass, id:"txt_hours" %> And here is the JS code snippet: $(function() { va ...

Retrieve the highest integer from the server-side for the client

When creating input fields of type number on the client side, I have been setting their max attribute to the maximum integer value in the user's browser using: Number.MAX_SAFE_INTEGER.toString() Now, I need to output an input field on the se ...

How can Vue.js deactivate or activate a dropdown based on a checkbox's state?

My task is to toggle the enabled/disabled state of a dropdown called combo-select when a checkbox is checked. The functionality works as expected when I click on Add Name, but not when I am in Editing Name mode and check the box for No Client. https://i.s ...

Using the mousewheel to scroll over an iframe is not functioning properly in Internet Explorer versions 8 through 11

I have implemented Perfect-Scrollbar, a jQuery script, which works well in Firefox, Safari, Chrome, and Opera. However, I am facing an issue with scrolling using the mouse wheel when it is used in combination with an iframe in Internet Explorer versions 8 ...

Fluid Design - Extra Spacing at the Bottom with Percent Margin-Top

Currently, I am working on developing a website using only percentages. However, I have encountered an issue with my main content section. I have set a margin-top of 10%, but this is causing excessive spacing at the bottom of the page and resulting in a sc ...

Replace the image with text inside an anchor when the anchor is being hovered

I want a logo (we'll call it .item-logo) to be shown inside a circle when not being hovered over, but when you hover over the container, the date should be displayed. Here is the HTML code: <div id="main-content" class="container animated"> ...

Ways to initiate a new animation once another one has concluded

I am looking to initiate a jQuery animation once another one has completed. Initially, there is a slide down effect towards the second navigation bar: $(".navigation-bar1").click(function() { $('html,body').animate({ scrollTop: $(". ...

Elevation Ratio

Is there a way to make the height of the textarea in my demo always be 50% of the frame's height, even when resizing the frame? Currently, the textarea's height does not adjust dynamically. How can I achieve this? html, body { line-heigh ...

Utilizing pusher for personalized, direct communication with individual recipients

I'm currently working on implementing a one-to-one communication system between a user and an admin using Laravel and Pusher. The user does not need to be logged in, they can simply visit the site and send a message to the admin. If there's an on ...

Creating an Efficient Lazy Loading HTML Page with jQuery

I've been looking to create a page that loads content only as the user scrolls to that specific section, similar to the way Pinterest website functions. Does anyone have suggestions on how to design and implement this feature, or know of any plugins ...

Drawing the canvas is taking place prior to the image being fully loaded in JavaScript

Currently, I am in the process of creating a collage using images that are all sized at 174x174 pixels. The images are stored on my server, and while my program can locate them successfully, it requires me to click the "save image" button twice for them to ...

Tips for customizing the appearance of Angular Material select drop down overlay

In my project, there is an angular component named currency-selector with its dedicated css file defining the styling as shown below: .currency-select { position: absolute; top: 5px; right: 80px; z-index: 1000000; color: #DD642A; f ...

"Encountering issues when trying to POST data from an Ember component to an

When attempting to post from a component in my Ember app to my Express API, I am encountering the following error: SyntaxError: Unexpected token V in JSON at position 0 Upon inspecting the response in the network inspector on Chrome, I found this error m ...

Utilizing a for loop to iterate through the results of child_process.spawnSync when executing a

First, I will share the code snippet below: Let me illustrate the issue I am encountering: for (var i = 0; i < arrayleng.length; i++) { var oneScript = spawnSync('python', ["/home/demo/mypython.py", arrayleng[i].path]); // console.lo ...

Tips for generating Sequelize models dynamically in NodeJS 14 using Sequelize version 6

My project relies on Node and Sequelize for its backend operations. Everything was smooth sailing until I decided to update both Node and Sequelize to their latest versions. Although I could revert back to the older versions, I'm hesitant because my o ...