Home > Enterprise >  How to create accordions so only 1 stays open at a time?
How to create accordions so only 1 stays open at a time?

Time:12-16

I am having some difficulty using using an accordion in HTML & JS. I am trying to code it so only one accordion is open at a time. If someone clicks and opens a new accordion, all the other should close. This my HTML.

 <div >
        <div >
          <div >
            HUMBER RADIO
          </div>
          <div >
            <div >
                <ul>
                    <li><a href="">RADIO NEWS</a></li>
                    <li><a href="">PODCAST</a></li>                 
                    <li><a href="">CONTENT</a></li>                
                </ul>
            </div>
          </div>
        </div>
        </div>
    
        <div >
            <div >
              <div >
                TV NEWS
              </div>
              <div >
                <div >
                    <ul>
                        <li><a href="">COVID UPDATES</a></li>
                        <li><a href="">NORTH CAMPUS NEWS</a></li>                 
                        <li><a href="">LAKESHORE CAMPUS NEWS</a></li>                
                    </ul>
                </div>
              </div>
            </div>
            </div>

Here is the JavaScript for the code. It can open all of them, but I am struggling to program it so the others close.

window.onload = pageReady;

function pageReady() {

    const accordionItemHeaders = document.querySelectorAll(".accordion-item-header");

    accordionItemHeaders.forEach(accordionItemHeader => {
      accordionItemHeader.addEventListener("click", event => {
    
        accordionItemHeader.classList.toggle("active");
        const accordionItemBody = accordionItemHeader.nextElementSibling;
        if(accordionItemHeader.classList.contains("active")) {
          accordionItemBody.style.maxHeight = "100px";
        }
        else {
          accordionItemBody.style.maxHeight = "0px";
        }
        
      });
    });
}

CodePudding user response:

A couple of tweaks:

  1. Before setting the currently clicked header to .active, we select the previously active header (if it exists) and remove that class.

  2. Instead of setting inline styles using JavaScript, here's the cleaner alternative of setting max-height using just CSS, with the adjacent sibling combinator (a plus sign) to select the accordion body that follows the active accordion header.

const accordionItemHeaders = document.querySelectorAll(".accordion-item-header");

accordionItemHeaders.forEach(accordionItemHeader => {
  accordionItemHeader.addEventListener("click", event => {
    if (event.target.classList.contains('active')) {
      accordionItemHeader.classList.remove("active");
    } else {
      document.querySelector(".accordion-item-header.active")?.classList.remove("active");
      accordionItemHeader.classList.add("active");
    }
  });
});
.accordion-item-header.active .accordion-item-body {
  max-height: 100px;
}

CodePudding user response:

Similar to Jon's excellent answer we are going to let CSS handle the styling and just use javascript to manipulate classes.

The main difference is we are going to accommodate multiple accordion groups and utilize event bubbling. The event listener will be attached to the accordion group and then check the event target. This is also handy if you end up injecting more elements into the accordions with JS.

//Get the Accordion Groups
const accordions = document.querySelectorAll(".accordion");


accordions.forEach(accordion => {
  //Add event listener to each ACCORDION , use function not fat arrow to get access to "this"
  accordion.addEventListener("click", function(event) {
    //Check the event targe is an item header
    if (event.target.matches(".accordion-item-header")) {
      //Get current active, here "this" refers to the accordion group clicked on
      let active = this.querySelector(".active");
      
      //Toggle element if active element clicked
      if (active == event.target) {
        event.target.classList.toggle("active");
      } else {
        //Remove current active.
        if (active) {
          active.classList.remove("active");
        }
        //Add active        
        event.target.classList.add("active");
      }
    }
  });
});
.accordion {
  width: 45%;
  display: inline-block;
  vertical-align: top;
}

.accordion .accordion-item-header .accordion-item-body {
  max-height: 0px;
  overflow: hidden;
  transition: all 0.5s;
}

.accordion .accordion-item-header.active .accordion-item-body {
  max-height: 100px;
}
<div >
  <h2>Accordion Group 1</h2>
  <div >
    <div >
      HUMBER RADIO
    </div>
    <div >
      <div >
        <ul>
          <li><a href="">RADIO NEWS</a></li>
          <li><a href="">PODCAST</a></li>
          <li><a href="">CONTENT</a></li>
        </ul>
      </div>
    </div>
  </div>
  <div >
    <div >
      TV NEWS
    </div>
    <div >
      <div >
        <ul>
          <li><a href="">COVID UPDATES</a></li>
          <li><a href="">NORTH CAMPUS NEWS</a></li>
          <li><a href="">LAKESHORE CAMPUS NEWS</a></li>
        </ul>
      </div>
    </div>
  </div>
</div>

<div >
  <h2>Accordion Group 1</h2>
  <div >
    <div >
      JJJ RADIO
    </div>
    <div >
      <div >
        <ul>
          <li><a href="">RADIO NEWS</a></li>
          <li><a href="">PODCAST</a></li>
          <li><a href="">CONTENT</a></li>
        </ul>
      </div>
    </div>
  </div>
  <div >
    <div >
      Radio NEWS
    </div>
    <div >
      <div >
        <ul>
          <li><a href="">COVID UPDATES</a></li>
          <li><a href="">NORTH CAMPUS NEWS</a></li>
          <li><a href="">LAKESHORE CAMPUS NEWS</a></li>
        </ul>
      </div>
    </div>
  </div>
</div>

CodePudding user response:

You don't need to stress yourself, just the bootstrap HTML JavaScript user interface library, you can Google search about it, they have every UI component you can use

  • Related