Skip to content Skip to sidebar Skip to footer

Vanilla Javascript Accordion Functionality

I need help with closing other panels once I open a click on a different panel. I have been trying to get my head around it for the past week but I'm just not able to. I don't wan

Solution 1:

Event Delegation


  1. Wrap everything in a block element.

    var main = document.querySelector(`main`)
    
  2. Add an EventListener to that "parent" element

    main.addEventListener('click', ....
    
  3. Now if mainor any descendants of main are clicked, a callback function will be invoked. So we have only one EventListener listening for a click event on the behalf of each .accordion. We determine which .accordion was actually clicked by using an if condition and the event.target property.

  4. The rule of mutual exclusivity applies to how an accordion works:

    • Only one .accordion + .panel combo can have the .active class.

    • Whenever it's time to change (in this case, e.target (the clicked element) has been clicked), all .accordions will remove the .active class (whether they actually had it or not).

    • After there are no element with the .active class, you then give it to e.target.


Changes


  • .accordion + .panel.active instead of .accordion.active.

  • .style.maxHeight replaced by class .active:

    .panel.active {
      max-height: 2000px;
      height:auto;
      overflow: hidden;
      transition: 0.2s ease-out;
    }
    

Demo

Details are commented in Demo


// Reference the parent of all .accordionvar main = document.querySelector('main');

/* Register main to click events...
|| when main or any of its descendant elements are clicked...
*/
main.addEventListener("click", function(e) {

  /* Collect all .accordion into a NodeList and convert it into
  || an array.
  */var acc = Array.from(document.querySelectorAll(".accordion"));
  
  /* Loop thru each .accordion  to remove the .active class
  || from each .panel
  */for (let a = 0; a < acc.length; a++) {
    var panel = acc[a].nextElementSibling;
    panel.classList.remove('active');
  }
  /* After nothing has class .active, assign .active to the
  || .panel of the clicked element (e.target)
  */if (e.target !== e.currentTarget) {
    var tgt = e.target.nextElementSibling;
    tgt.classList.add("active");
  }
});
.accordion {
  background-color: #2364aa;
  color: #ffffff;
  cursor: pointer;
  padding: 18px;
  border: none;
  text-align: left;
  outline: none;
  font-size: 21px;
  transition: 0.4s;
}

.open,
.accordion:hover {
  background-color: #205A99;
}

.accordion:after {
  content: '\f067';
  font-family: "Font Awesome 5 Free";
  color: #ffffff;
  float: right;
  font-size: 1.25em;
  line-height: 25px;
}

.open:after {
  content: "\2212";
}

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

.panel.active {
  max-height: 2000px;
  height:auto;
  overflow: hidden;
  transition: 0.2s ease-out;
}

@mediaonly screen and (min-width: 960px) {
  .container {
    display: table;
    box-sizing: border-box;
  }
  .row.col {
    margin: 10px0;
  }
  .col {
    display: table-cell;
  }
  .col.middle {
    vertical-align: middle;
  }
  .col-2 {
    width: 50%;
    padding-right: 72px;
  }
  .col-4 {
    width: 33.33333333333333333%;
    padding-right: 72px;
  }
}
<!DOCTYPE html><html><head><metaname="viewport"content="width=device-width, initial-scale=1"></head><body><main><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping &amp; Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping & Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping & Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping & Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div></main></body></html>

Solution 2:

I hope this function helps you

function closeAll() {
  var accs = document.querySelectorAll('.accordion');
  for(var i = 0; i < accs.length; i ++) {
    accs[i].classList.remove('active');
    var panel = accs[i].nextElementSibling;
    panel.style.maxHeight = null;
  }
}

Update We can skip closing clicked element by adding this condition to closeAll function:

if (accs[i] == tar) {
  continue;
}

Full code here

var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].addEventListener("click", function(ev) {
    closeAll(ev.target);
    this.classList.toggle("active");
    var panel = this.nextElementSibling;
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  });
}

functioncloseAll(tar) {
  var accs = document.querySelectorAll('.accordion');
  for (var i = 0; i < accs.length; i++) {
    if (accs[i] == tar) {
      continue;
    }
    accs[i].classList.remove('active');
    var panel = accs[i].nextElementSibling;
    panel.style.maxHeight = null;
  }
}
.accordion {
  background-color: #2364aa;
  color: #ffffff;
  cursor: pointer;
  padding: 18px;
  border: none;
  text-align: left;
  outline: none;
  font-size: 21px;
  transition: 0.4s;
}

.open,
.accordion:hover {
  background-color: #205A99;
}

.accordion:after {
  content: '\f067';
  font-family: "Font Awesome 5 Free";
  color: #ffffff;
  float: right;
  font-size: 1.25em;
  line-height: 25px;
}

.open:after {
  content: "\2212";
}

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

.panel-body {
  padding: 18px0;
}

@mediaonly screen and (min-width: 960px) {
  .container {
    display: table;
    box-sizing: border-box;
  }
  .row.col {
    margin: 10px0;
  }
  .col {
    display: table-cell;
  }
  .col.middle {
    vertical-align: middle;
  }
  .col-2 {
    width: 50%;
    padding-right: 72px;
  }
  .col-4 {
    width: 33.33333333333333333%;
    padding-right: 72px;
  }
}
<html><head><metaname="viewport"content="width=device-width, initial-scale=1"><linkrel="stylesheet"href="accordion.css"></head><body><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping & Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div><h3class="accordion">Basics of Sailing</h3><divclass="panel"><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Before Choosing a Sailboat</h4><p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Car Topping & Trailing</h4><p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p></div><divclass="col col-4 middle"><!-- <div class="space"></div> --><h4>Safety Equipment</h4><p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p></div></div><scriptsrc="accordion.js"></script></body></html>

Solution 3:

This is a class called Accordion in Vanilla js. It mostly shows the functionality in javascript , style is not good :)

classAccordion {
      constructor(AccordionData) {

        // Statethis.data = AccordionData;


        // View Layerthis.mainContainer = document.querySelector('.container');
        this.allAccordionDetailsElements = [];


        this.init();
      }

      init() {
        this.createAccordions();
        this.bindEvents();
      }

      createAccordions() {
        this.data.forEach(acc => {
          let accordionHTML = this.generateHTML(acc);

          this.mainContainer.appendChild(accordionHTML);
        });

        this.allAccordionDetailsElements = document.querySelectorAll('.accordion-details');

      }

      checkIfCurrentTarget(targetEl, detailsEl) {
        return detailsEl.dataset.target === targetEl.id;
      }

      getDisplayStatus(element) {
        return element.style.display;
      }

      toggleDetailsVisibility(detailsEl) {
        const isVisible = this.getDisplayStatus(detailsEl) === 'block';

        if (!isVisible) {
          detailsEl.style.display = 'block';
        } else {
          detailsEl.style.display = 'none';
        }


      }

      hideAllDetails() {
        this.allAccordionDetailsElements.forEach(detailsSection => {
          detailsSection.style.display = 'none';
        });
      }


      bindEvents() {

        this.mainContainer.addEventListener('click', (e) => {
          if (typeof e === 'undefined') return;

          const targetEl = e.target;
          const isAccordionHeader = targetEl.classList.contains('accordion-header');


          if (isAccordionHeader) {

            this.hideAllDetails();

            this.allAccordionDetailsElements.forEach(detailsSection => {
              if (this.checkIfCurrentTarget(targetEl, detailsSection)) {
                this.toggleDetailsVisibility(detailsSection)
              }
            });
          }

        });

      }

      generateHTML(accordionElData) {
        const { id, headerText, detailsText } = accordionElData;

        const sectionEl = document.createElement('section');
        sectionEl.className = 'accordion-container';

        const headerEl = document.createElement('button');
        headerEl.type = 'button';
        headerEl.className = 'accordion-header';
        headerEl.textContent = headerText;
        headerEl.id = id;


        const articleEl = document.createElement('article');
        articleEl.className = 'accordion-details';
        articleEl.textContent = detailsText;
        articleEl.dataset.target = id;

        sectionEl.appendChild(headerEl);
        sectionEl.appendChild(articleEl);

        return sectionEl;

      }
    }

    constAccordionData = [
      {
        id: 'acc-1',
        headerText: 'Section 1',
        detailsText: 'This is dummy Text for Section 1'

      },
      {
        id: 'acc-2',
        headerText: 'Section 2',
        detailsText: 'This is dummy Text for Section 2'

      },
      {
        id: 'acc-3',
        headerText: 'Section 3',
        detailsText: 'This is dummy Text for Section 3'

      }

    ];


    window.addEventListener('DOMContentLoaded', () => {

      const accordion = newAccordion(AccordionData);

    });
 * {
      box-sizing: border-box;
      padding: 0;
      margin: 0;
    }

    .accordion-details {
      display: none;
    }
<mainclass="container"></main>

Post a Comment for "Vanilla Javascript Accordion Functionality"