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

247
Vistas
Make accordion item open by default

In my accordion set I'm trying to get the first accordion item open by default on page load.

I'm adding the class .open to that element, like such:

<button class="open">

This seems to work but the problem is when I click on that same element instead of closing it, it keeps re-opening it and by looking at the JS script I don't quite understand what could be the problem.

Demo

var accordionButton = document.querySelectorAll("button");

for (var i = 0; i < accordionButton.length; i++) {
  accordionButton[i].addEventListener("click", switchClasses);
}

function switchClasses() {
  for (var i = 0; i < accordionButton.length; i++) {
    if (this !== accordionButton[i]) {
      accordionButton[i].classList.remove("open");
      accordionButton[i].nextElementSibling.style.maxHeight = null;
    }
  }
  this.classList.toggle("open");
  var nextAccordionButton = this.nextElementSibling;
  if (nextAccordionButton.style.maxHeight) {
    nextAccordionButton.style.maxHeight = null;
  } else {
    nextAccordionButton.style.maxHeight =
      nextAccordionButton.scrollHeight + "px";
  }
}
.accordion-item {
  border: 1px solid lightgrey;
}

button {
  background: none;
  border: none;
  width: 100%;
  max-width: none;
  height: auto;
  padding: 12px;
  text-align: left;
  cursor: pointer;
  transition: 0.5s;
}

.content-wrapper {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

.content {
  padding: 0 10px;
}

.open {
  background: lightgray;
  border-bottom: none;
}

.open + .content-wrapper {
  max-height: none;
}
<div class="accordion-item">
  <button class="open">
    <span class="accordion__title">Accordion 1</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 1 content.
    </div>
  </div>
</div>
<div class="accordion-item">
  <button>
    <span class="accordion__title">Accordion 2</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 2 content.
    </div>
  </div>
</div>
<div class="accordion-item">
  <button>
    <span class="accordion__title">Accordion 3</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 3 content.
    </div>
  </div>
</div>

almost 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

You also have to check for the currently clicked element. What happened was that you were constantly re-applying open to the element right after removing it.

Also, try to use const for variables that wont be re-assigned. and let for variables that will be mutated. var keyword is not advised.

const accordionButton = document.querySelectorAll('button');

for (let i = 0; i < accordionButton.length; i++) {
  accordionButton[i].addEventListener('click', switchClasses);
}

function switchClasses() {
  for (let i = 0; i < accordionButton.length; i++) {
    if (this !== accordionButton[i]) {
      accordionButton[i].classList.remove('open');
      accordionButton[i].nextElementSibling.style.maxHeight = null;
      continue;
    }

    if (this === accordionButton[i]) {
      if (!this.classList.contains('open')) {
        this.classList.add('open');
        const nextAccordionButton = this.nextElementSibling;
        nextAccordionButton.style.maxHeight =
          nextAccordionButton.scrollHeight + 'px';
      } else {
        accordionButton[i].classList.remove('open');
        accordionButton[i].nextElementSibling.style.maxHeight = null;
      }
    }
  }
}
.accordion-item {
  border: 1px solid lightgrey;
}

button {
  background: none;
  border: none;
  width: 100%;
  max-width: none;
  height: auto;
  padding: 12px;
  text-align: left;
  cursor: pointer;
  transition: 0.5s;
}

.content-wrapper {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

.content {
  padding: 0 10px;
}

.open {
  background: lightgray;
  border-bottom: none;
}

.open+.content-wrapper {
  max-height: none;
}
<div class="accordion-item">
  <button class="open">
    <span class="accordion__title">Accordion 1</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 1 content.</p>
    </div>
  </div>
</div>
<div class="accordion-item">
  <button>
    <span class="accordion__title">Accordion 2</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 2 content.</p>
    </div>
  </div>
</div>
<div class="accordion-item">
  <button>
    <span class="accordion__title">Accordion 3</span>
  </button>
  <div class="content-wrapper">
    <div class="content">
      <p>Accordion 3 content.</p>
    </div>
  </div>
</div>

almost 4 years ago · Santiago Trujillo Denunciar

0

Here is a simple accordion example to simplify your problem/structure. On click, I remove open if the clicked element has the class. Else, I remove the class if an accordion is opened, then I open the clicked accordion.

document.querySelectorAll("button").forEach((e) => {
  e.addEventListener("click", () => {
    if (e.classList.contains("open")) {
      e.classList.remove("open")
    } else {
      let opened = document.querySelector("button.open")
      if (opened) {
        opened.classList.remove("open")
      }
      e.classList.add("open")
    }
  })
});
.content {
  display: none;
}

button {
  display: block;
}

.open {
  background-color: orange;
}

.open+.content {
  display: block;
}
<button class="open">Accordion 1</button>
<div class="content">Content 1</div>
<button>Accordion 2</button>
<div class="content">Content 2</div>
<button>Accordion 3</button>
<div class="content">Content 3</div>

Also if you want to allow multiple accordions opened at the same time, you can make it only with HTML and CSS using checkboxes.

input {
  display: none;
}

label {
  display: block;
  width: fit-content;
}

input:checked+label {
  background-color: orange;
}

.content {
  display: none;
}

input:checked+label+.content {
  display: block;
}
<input type="checkbox" id="accordion-1" checked/>
<label class="btn" for="accordion-1">Accordion 1</label>
<div class="content">Content 1</div>
<input type="checkbox" id="accordion-2" />
<label class="btn" for="accordion-2">Accordion 2</label>
<div class="content">Content 2</div>
<input type="checkbox" id="accordion-3" />
<label class="btn" for="accordion-3">Accordion 3</label>
<div class="content">Content 3</div>

almost 4 years ago · Santiago Trujillo 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