Home > database >  Accordion that closes when another tab is clicked
Accordion that closes when another tab is clicked

Time:09-13

I think I may have been staring at this problem for too long and missing something simple. I can create an accordion that opens and closes each tab on click. But when I tried to revise the code so that each tab closes when clicked on another automatically, the tab you click on will no longer close itself once clicked. I have shortened the code a bit and will be adjusting the aria labels later, but why won't the tab close when clicked on itself? The active class isn't being removed.

JSFiddle here: https://jsfiddle.net/huz08qts/6/

  document.addEventListener("DOMContentLoaded", () => {
     const toggleClasses = (a) => {
        let collapser = a.querySelector(".accordion-collapser");
        let panel = a.querySelector(".accordion-panel");
        let title = a.querySelector(".accordion-title");
        document.querySelectorAll(".active").forEach(e => e.classList.remove("active"))
      
        if(panel.classList.contains("active")) {
            panel.classList.remove("active");
        } else {
            panel.classList.add("active");

        }
        // title.classList.add("active");

      }
       document.querySelectorAll(".accordion").forEach((a) => {
          a.addEventListener("click", () => toggleClasses(a), false)
      
        });
  })
      html {
        box-sizing: border-box;
        font-family: Arial, Helvetica, sans-serif;
      }
      *,
      *:before,
      *:after {
        box-sizing: inherit;
      }

      .container {
        max-width: 800px;
        margin: 0 auto;
      }

      .accordion-icon {
        height: 50px;
        width: 50px;
        margin-left: 10px;
      }

      .accordion-group {
        margin-bottom: 21px;
      }

      .accordion-heading {
        padding: 0;
        margin: 0;
        border: 1px solid #cccccc;
        border-top: 0px;
        border-bottom: 0px;
        position: relative;
        display: flex;
        align-items: center;
      }

      .accordion-heading:focus-within {
        outline: 5px auto -webkit-focus-ring-color;
        outline-offset: -2px;
        outline-style: dotted;
        outline-width: 2px;
      }

      .accordion-group .accordion-heading:first-child {
        border-top: 1px solid #cccccc;
      }

      .accordion-group .accordion:last-child .accordion-heading {
        border-bottom: 1px solid #cccccc;
      }

      .accordion-group .accordion:last-child .accordion-panel {
        border-top: 0;
      }

      .accordion-title {
        color: #363c3e;
        line-height: 1.3em;
        font-weight: 600;
        font-size: 18px;
      }

      .accordion-heading a {
        position: relative;
      }

      .accordion-title:hover {
        color: #00a950;
        cursor: pointer;
      }

      .accordion-heading:hover {
        cursor: pointer;
      }

      .accordion-heading h3:after {
        content: " ";
        background: url("https://i.postimg.cc/13fCTwcc/collapse-icon.png");
        position: absolute;
        top: 50%;
        right: 15px;
        width: 37px;
        height: 37px;
        transform: translateY(-50%) rotate(0);
        transition: transform 0.3s, -webkit-transform 0.3s;
      }

      .accordion-heading h3.active:after {
        transform: translateY(-50%) rotate(-45deg);
      }

      .accordion-collapser {
        display: inline-block;
        color: #363c3e;
        padding: 10px 55px 10px 15px;
        text-decoration: none;
      }
      .accordion-collapser:focus {
        outline: 0px;
      }
      .accordion-collapser:hover {
        color: #00a950;
        text-decoration: none;
      }

      .accordion-panel {
        background: #fbfbfb;
        line-height: 1.42;
        font-size: 16px;
        display: none;
        padding: 15px 55px 15px 25px;
        height: 0px;
        max-height: 0px;
        transition: max-height 0.5s ease-out;
      }

      .accordion-group .accordion:last-child .accordion-panel {
        border-bottom: 1px solid #cccccc;
      }

      .accordion-panel.active {
        border: 1px solid #cccccc;
        border-bottom: 0px;
        display: block;
        /* This will need to be adjusted accordingly once you know the avg elem size */
        /* For transition use only  */
        max-height: 800px;
        height: auto;
        overflow: hidden;
      }

      @media (max-width: 500px) {
        .accordion-heading h3 > a {
          font-size: 16px;
        }

        .accordion-panel {
          font-size: 15px;
        }
      }
   <section >
      <div  role="tablist" aria-multiselectable="true" id="accordion-mortgage">
        <div >
          <div  role="tab">
            <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
            <h3 >
              <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
            </h3>
          </div>
          <div  role="tabpanel" aria-expanded="false">
            <div >I am the accordion's body content!</div>
          </div>
        </div>
        <div >
          <div  role="tab">
            <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
            <h3 >
              <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
            </h3>
          </div>
          <div  role="tabpanel" aria-expanded="false">
            <div >
              <p>
                I am the accordion's body content! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
              </p>
              <p>
                quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
                pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
              </p>
              <ul>
                <li>List item</li>
                <li>List item</li>
                <li>List item</li>
                <ul>
                  <li>List item</li>
                  <li>List item</li>

                  <li>List item</li>
                </ul>
              </ul>
            </div>
          </div>
        </div>
      </div>
    </section>

CodePudding user response:

I made the following change in your code and it's working fine now

  1. Added a boolean flag that saved the state of clicked accordion (before everything is closed)
  2. Used this flag to set the state of accordion (after everything is closed)
        let isActive= panel.classList.contains("active");
        document.querySelectorAll(".active").forEach(e => e.classList.remove("active"))
      
        if(!isActive) {
            panel.classList.add("active");
        }

JS Fiddle: https://jsfiddle.net/aadeshk/Lb04v7qe/

CodePudding user response:

Since you are removing all active classes then you can't really toggle them, unless you remember first the state.

document.addEventListener("DOMContentLoaded", () => {
  const toggleClasses = (a) => {
    let collapser = a.querySelector(".accordion-collapser");
    let panel = a.querySelector(".accordion-panel");
    let title = a.querySelector(".accordion-title");
    var flag = panel.classList.contains("active")
    document.querySelectorAll(".active").forEach(e => e.classList.remove("active"))

    if (flag) {
      panel.classList.remove("active");
    } else {
      panel.classList.add("active");

    }
    // title.classList.add("active");

  }
  document.querySelectorAll(".accordion").forEach((a) => {
    a.addEventListener("click", () => toggleClasses(a), false)

  });
})
html {
  box-sizing: border-box;
  font-family: Arial, Helvetica, sans-serif;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

.container {
  max-width: 800px;
  margin: 0 auto;
}

.accordion-icon {
  height: 50px;
  width: 50px;
  margin-left: 10px;
}

.accordion-group {
  margin-bottom: 21px;
}

.accordion-heading {
  padding: 0;
  margin: 0;
  border: 1px solid #cccccc;
  border-top: 0px;
  border-bottom: 0px;
  position: relative;
  display: flex;
  align-items: center;
}

.accordion-heading:focus-within {
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
  outline-style: dotted;
  outline-width: 2px;
}

.accordion-group .accordion-heading:first-child {
  border-top: 1px solid #cccccc;
}

.accordion-group .accordion:last-child .accordion-heading {
  border-bottom: 1px solid #cccccc;
}

.accordion-group .accordion:last-child .accordion-panel {
  border-top: 0;
}

.accordion-title {
  color: #363c3e;
  line-height: 1.3em;
  font-weight: 600;
  font-size: 18px;
}

.accordion-heading a {
  position: relative;
}

.accordion-title:hover {
  color: #00a950;
  cursor: pointer;
}

.accordion-heading:hover {
  cursor: pointer;
}

.accordion-heading h3:after {
  content: " ";
  background: url("https://i.postimg.cc/13fCTwcc/collapse-icon.png");
  position: absolute;
  top: 50%;
  right: 15px;
  width: 37px;
  height: 37px;
  transform: translateY(-50%) rotate(0);
  transition: transform 0.3s, -webkit-transform 0.3s;
}

.accordion-heading h3.active:after {
  transform: translateY(-50%) rotate(-45deg);
}

.accordion-collapser {
  display: inline-block;
  color: #363c3e;
  padding: 10px 55px 10px 15px;
  text-decoration: none;
}

.accordion-collapser:focus {
  outline: 0px;
}

.accordion-collapser:hover {
  color: #00a950;
  text-decoration: none;
}

.accordion-panel {
  background: #fbfbfb;
  line-height: 1.42;
  font-size: 16px;
  display: none;
  padding: 15px 55px 15px 25px;
  height: 0px;
  max-height: 0px;
  transition: max-height 0.5s ease-out;
}

.accordion-group .accordion:last-child .accordion-panel {
  border-bottom: 1px solid #cccccc;
}

.accordion-panel.active {
  border: 1px solid #cccccc;
  border-bottom: 0px;
  display: block;
  /* This will need to be adjusted accordingly once you know the avg elem size */
  /* For transition use only  */
  max-height: 800px;
  height: auto;
  overflow: hidden;
}

@media (max-width: 500px) {
  .accordion-heading h3>a {
    font-size: 16px;
  }
  .accordion-panel {
    font-size: 15px;
  }
}
<section >
  <div  role="tablist" aria-multiselectable="true" id="accordion-mortgage">
    <div >
      <div  role="tab">
        <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
        <h3 >
          <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
        </h3>
      </div>
      <div  role="tabpanel" aria-expanded="false">
        <div >I am the accordion's body content!</div>
      </div>
    </div>
    <div >
      <div  role="tab">
        <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
        <h3 >
          <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
        </h3>
      </div>
      <div  role="tabpanel" aria-expanded="false">
        <div >
          <p>
            I am the accordion's body content! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
          </p>
          <p>
            quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
            officia deserunt mollit anim id est laborum.
          </p>
          <ul>
            <li>List item</li>
            <li>List item</li>
            <li>List item</li>
            <ul>
              <li>List item</li>
              <li>List item</li>

              <li>List item</li>
            </ul>
          </ul>
        </div>
      </div>
    </div>
  </div>
</section>

CodePudding user response:

  1. You need to use closest to reach the parent accordion then get the accordion-panel
  2. When you remove the active class from the other panels after filtering the current panel
  3. You can use classList.toggle instead of if/else condition.

document.addEventListener("DOMContentLoaded", () => {
     const toggleClasses = (a) => {
        let collapser = a.querySelector(".accordion-collapser");
        let panel = a.closest('.accordion').querySelector(".accordion-panel");
        let title = a.closest('.accordion').querySelector(".accordion-title");
        [...document.querySelectorAll(".active")].filter(i => i !== panel).forEach(e => e.classList.remove("active"))
        panel.classList.toggle("active")
      }
       document.querySelectorAll(".accordion").forEach((a) => {
          a.addEventListener("click", () => toggleClasses(a), false)
      
        });
  })
html {
        box-sizing: border-box;
        font-family: Arial, Helvetica, sans-serif;
      }
      *,
      *:before,
      *:after {
        box-sizing: inherit;
      }

      .container {
        max-width: 800px;
        margin: 0 auto;
      }

      .accordion-icon {
        height: 50px;
        width: 50px;
        margin-left: 10px;
      }

      .accordion-group {
        margin-bottom: 21px;
      }

      .accordion-heading {
        padding: 0;
        margin: 0;
        border: 1px solid #cccccc;
        border-top: 0px;
        border-bottom: 0px;
        position: relative;
        display: flex;
        align-items: center;
      }

      .accordion-heading:focus-within {
        outline: 5px auto -webkit-focus-ring-color;
        outline-offset: -2px;
        outline-style: dotted;
        outline-width: 2px;
      }

      .accordion-group .accordion-heading:first-child {
        border-top: 1px solid #cccccc;
      }

      .accordion-group .accordion:last-child .accordion-heading {
        border-bottom: 1px solid #cccccc;
      }

      .accordion-group .accordion:last-child .accordion-panel {
        border-top: 0;
      }

      .accordion-title {
        color: #363c3e;
        line-height: 1.3em;
        font-weight: 600;
        font-size: 18px;
      }

      .accordion-heading a {
        position: relative;
      }

      .accordion-title:hover {
        color: #00a950;
        cursor: pointer;
      }

      .accordion-heading:hover {
        cursor: pointer;
      }

      .accordion-heading h3:after {
        content: " ";
        background: url("https://i.postimg.cc/13fCTwcc/collapse-icon.png");
        position: absolute;
        top: 50%;
        right: 15px;
        width: 37px;
        height: 37px;
        transform: translateY(-50%) rotate(0);
        transition: transform 0.3s, -webkit-transform 0.3s;
      }

      .accordion-heading h3.active:after {
        transform: translateY(-50%) rotate(-45deg);
      }

      .accordion-collapser {
        display: inline-block;
        color: #363c3e;
        padding: 10px 55px 10px 15px;
        text-decoration: none;
      }
      .accordion-collapser:focus {
        outline: 0px;
      }
      .accordion-collapser:hover {
        color: #00a950;
        text-decoration: none;
      }

      .accordion-panel {
        background: #fbfbfb;
        line-height: 1.42;
        font-size: 16px;
        display: none;
        padding: 15px 55px 15px 25px;
        height: 0px;
        max-height: 0px;
        transition: max-height 0.5s ease-out;
      }

      .accordion-group .accordion:last-child .accordion-panel {
        border-bottom: 1px solid #cccccc;
      }

      .accordion-panel.active {
        border: 1px solid #cccccc;
        border-bottom: 0px;
        display: block;
        /* This will need to be adjusted accordingly once you know the avg elem size */
        /* For transition use only  */
        max-height: 800px;
        height: auto;
        overflow: hidden;
      }

      @media (max-width: 500px) {
        .accordion-heading h3 > a {
          font-size: 16px;
        }

        .accordion-panel {
          font-size: 15px;
        }
      }
<section >
      <div  role="tablist" aria-multiselectable="true" id="accordion-mortgage">
        <div >
          <div  role="tab">
            <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
            <h3 >
              <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
            </h3>
          </div>
          <div  role="tabpanel" aria-expanded="false">
            <div >I am the accordion's body content!</div>
          </div>
        </div>
        <div >
          <div  role="tab">
            <img src="https://i.postimg.cc/4xBs2Fjm/icons8-corgi-60.png"  />
            <h3 >
              <a role="button"  aria-expanded="false" data-parent="#accordion-mortgage" href="#">Lorem Ipsum</a>
            </h3>
          </div>
          <div  role="tabpanel" aria-expanded="false">
            <div >
              <p>
                I am the accordion's body content! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
              </p>
              <p>
                quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
                pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
              </p>
              <ul>
                <li>List item</li>
                <li>List item</li>
                <li>List item</li>
                <ul>
                  <li>List item</li>
                  <li>List item</li>

                  <li>List item</li>
                </ul>
              </ul>
            </div>
          </div>
        </div>
      </div>
    </section>

  • Related