Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

242
Vistas
How to get all siblings of a parent item with specific classes in Vanilla JS

I have a long list of list items (generated via an API) and I would like to show/hide some of the items with click, something like an accordion effect.

The list items that I would like to hide by default have P-item class, and the M-item class above them is what it should be triggering them to show.

Here is my markup:

<li class="session-item M-item"></li>
<li class="session-item P-item"></li>
<li class="session-item P-item"></li>
<li class="session-item G-item"></li>

P-items are children of their parent M-item. So by default in the above example, the two P-items should be hidden and M-item and G-item should be showing. When M-item is clicked, then the two hidden P-items show. I am only listing 4 items in the above example but the list goes on and the only separator between this relationship is the G-items.

I got it to work but it's only showing/hiding the first direct sibling of M-item, I used nextElementSibling, like this:

var acc = document.getElementsByClassName("M-item");
    var i;

    for (i = 0; i < acc.length; i++) {
        acc[i].addEventListener("click", function () {
            this.classList.toggle("active");
            var panel = this.nextElementSibling;
            if (panel.style.display === "block") {
                panel.style.display = "none";
            } else {
                panel.style.display = "block";
            }
        });
    }

What's the best way to select all siblings with the P-item and then break, looks for another M-item and repeat?

Is there something similar to nextAll(); in Vanilla JS? Do I need a while loop to iterate over the next sibling?

Here's how my full markup looks like:

enter image description here

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

My answer looks kinda like original, but uses a while loop to hide all following <li> tags as long as they have class .P-item. Loop stops if next element does not have that class, hence only hiding those P-items directly following the M-item that was pressed. Try it by copy pasting the whole code following here:

<!DOCTYPE html>

<head>
    <meta charset="utf-8">
    <style>
        .M-item {
            background-color: red;
            color: blue;
        }

        .active {
            background-color: pink;
        }

        .hide {
            display: none;
        }
    </style>
</head>

<body>
    <ul class="agenda">
        <li class="session-item M-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item M-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item M-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
        <li class="session-item P-item">something</li>
    </ul>
    <script>
        var acc = document.getElementsByClassName("M-item");
        var i;
        for (i = 0; i < acc.length; i++) {
            acc[i].addEventListener("click", function () {
                this.classList.toggle("active");
                let next = this.nextElementSibling;

                while (next.classList.contains('P-item')) {
                    next.classList.toggle('hide');
                    next = next.nextElementSibling;
                }
            });
        }
    </script>
</body>
</html>
about 4 years ago · Juan Pablo Isaza Denunciar

0

I think the OP aims to find adjacent siblings with the same class.

One idea would be to intervene a little earlier, before the li's are setup as siblings, and impose an html structure there, grouping the like-classed siblings in div's (or ul's). But, if we're starting from the already built list, it can be handled as a reduce on the collection of li's...

const sessionItems = document.getElementsByClassName("session-item");

let groups = Array.from(sessionItems).reduce((acc, el, index) => {
  const pItem = el.classList.contains("p-item")
  const delimeter = !pItem || index===0;
  if (delimeter) acc.push([]);
  if (pItem) acc[acc.length-1].push(el);
  return acc
}, []);

// now do whatever we want to the groups, like change visibility
// for clarity in this example, add a color class
groups.forEach((group, index) => {
  group.forEach(el => el.classList.add(`color-${index}`))
});
.color-0 {
  color: red;
}

.color-1 {
  color: green;
}
<ul>
  <li class="session-item m-item">item A</li>
  <li class="session-item p-item">item B</li>
  <li class="session-item p-item">item C</li>
  <li class="session-item m-item">item D</li>
  <li class="session-item p-item">item E</li>
  <li class="session-item p-item">item F</li>
  <li class="session-item p-item">item G</li>
  <li class="session-item m-item">item H</li>
</ul>

about 4 years ago · Juan Pablo Isaza Denunciar

0

You can maintain the visibility of the P items through CSS only, based on the "active" that the preceding M item has. This means the JS code only has to manage the toggling of the "active" class on the M item:

const ul = document.querySelector(".cad-agenda");
ul.addEventListener("click", function (e) {
    const mItem = e.target;
    if (!mItem.classList.contains("M-item")) return;
    const wasActive = mItem.classList.contains("active");
    document.querySelector(".active")?.classList?.remove("active");
    mItem.classList.toggle("active", !wasActive);
});
.P-item { display: none }
.active ~ .P-item:not(.active ~ .M-item ~ .P-item) { display: block }
.M-item { cursor: pointer; font-weight: bold }
<ul class="cad-agenda accordion accordion-1">
    <li class="session-item M-item">M-1</li>
    <li class="session-item P-item">P-1.1</li>
    <li class="session-item P-item">P-1.2</li>
    <li class="session-item G-item">G-1</li>
    <li class="session-item M-item">M-2</li>
    <li class="session-item P-item">P-2.1</li>
    <li class="session-item P-item">P-2.2</li>
    <li class="session-item M-item">M-3</li>
    <li class="session-item P-item">P-3.1</li>
    <li class="session-item P-item">P-3.2</li>
    <li class="session-item Press-item">PressItem</li>
    <li class="session-item M-item">M-3</li>
    <li class="session-item P-item">P-3.1</li>
    <li class="session-item M-item">M-4</li>
    <li class="session-item P-item">P-4.1</li>
    <li class="session-item M-item">M-5</li>
    <li class="session-item P-item">P-5.1</li>
    <li class="session-item G-item">G-2</li>
    <li class="session-item M-item">M-6 (has no P)</li>
    <li class="session-item -item">empty 1</li>
    <li class="session-item -item">empty 2</li>
    <li class="session-item -item">empty 3</li>
    <li class="session-item M-item">M-7 (has no P)</li>
    <li class="session-item M-item">M-8</li>
    <li class="session-item P-item">P-8.1</li>
    <li class="session-item P-item">P-8.2</li>
</ul>

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda