Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

246
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda