Sunday, 20 February 2022

How to use JavaScript to apply slidedown functionality in accordion?

In this snippet below, I'm trying to apply a slide down functionality to each panel when opened. The result is that slide down is working.

The problem is...

  1. In mobile, when a second panel is opened, the first panel remains at full height.

  2. Slide up functionality isn't working as expected.

Lastly, I have hundreds of these accordions on my site. I need to be able to update the JS/CSS accordingly, without changing the HTML markup.

How do I apply JavaScript slide up/down functionality to accordion panels when opened?

function initAccordion() {
  let handlePanelClick = (e) => {
    showPanel(e.currentTarget.parentNode);
  };

  function showPanel(panel) {
    let isWide = isWideScreen();
    let isActive = panel.classList.contains("active");

    if (!isActive) {
      panel.classList.add("active");
      panel.style.height = "auto";

      var height = panel.clientHeight + "px";

      panel.style.height = "0px";

      setTimeout(() => {
        panel.style.height = height
      }, 0);
    } else {
      panel.style.height = "auto";

      panel.addEventListener(
        "transitionend",
        () => {
          panel.classList.remove("active");
        }, {
          once: true
        }
      );
    }

    if (isWide) {
      if (!isActive) {
        panel.classList.add("active");
      } else {
        panel.classList.remove("active");
      }
    } else {
      // handle mobiles
      let panels = document.querySelectorAll(".panel");
      panels.forEach((p) => p.classList.remove("active"));
      if (!isActive) {
        // open the panel
        panel.classList.add("active");
      }
    }
  }

  let allPanelElements = document.querySelectorAll(".panel");
  allPanelElements.forEach((allPanels) =>
    allPanels
    .querySelector(".acc-trigger")
    .addEventListener("click", handlePanelClick)
  );
}

let isWideScreen = () => {
  return window.matchMedia("(min-width: 992px)").matches;
};
initAccordion(document.getElementsByClassName("accordion"));
.wrapper {
  margin: 50px auto 0;
  display: flex;
  flex-direction: column;
}
.wrapper a {
  text-decoration: none;
}
.wrapper button {
  border-style: none;
  background: white;
}
.wrapper button::-moz-focus-inner {
  border: 0;
}
.wrapper .accordion:first-child {
  margin-right: 1rem;
}
.wrapper .accordion .panel {
  min-height: unset;
  margin: 0;
  border-bottom: 1px solid #000A70;
  transition: height 1s ease;
  overflow: hidden;
}
.wrapper .accordion .panel .acc-trigger {
  display: block;
  font-weight: 400;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: left;
  width: 100%;
  cursor: pointer;
  background: 0 0;
}
.wrapper .accordion .panel .acc-trigger .acc-title {
  display: flex;
  align-items: center;
  outline: 0;
  padding-bottom: 0.5rem;
  transition: all 1s ease;
}
.wrapper .accordion .panel .acc-trigger .acc-title:hover svg.acc-icon path {
  fill: #005fec;
}
.wrapper .accordion .panel .acc-trigger .acc-title h4 {
  font-weight: 800;
  color: #000A70;
  font-size: 1.25rem;
  justify-content: space-between;
  margin-right: 1rem;
  outline: 0;
  transition: all 1s ease;
}
.wrapper .accordion .panel .acc-trigger .acc-title h4:hover {
  color: #005fec;
}
.wrapper .accordion .panel .acc-trigger .acc-title svg.acc-icon {
  cursor: pointer;
  pointer-events: none;
  margin-left: auto;
  z-index: 3;
}
.wrapper .accordion .panel .acc-body {
  height: 0;
  opacity: 0;
  overflow: hidden;
  visibility: hidden;
  transition: height 1s ease-out, opacity 1s ease-out;
}
.wrapper .accordion .panel .acc-body ol.custom-list {
  list-style-type: none;
  -webkit-margin-before: 0;
  margin-block-start: 0;
  -webkit-margin-after: 0;
  margin-block-end: 0;
  counter-reset: my-awesome-counter;
}
.wrapper .accordion .panel .acc-body ol.custom-list li {
  counter-increment: my-awesome-counter;
  padding-left: 1.125rem;
  margin: 2rem 0;
  font-size: 1rem;
  line-height: 1.5rem;
  color: #000A70;
}
.wrapper .accordion .panel .acc-body ol.custom-list li::before {
  content: counter(my-awesome-counter) ". ";
  color: #005fec;
}
.wrapper .accordion .panel .acc-body ol.custom-list li:first-child {
  margin-top: 0;
}
.wrapper .accordion .panel .acc-body ol.custom-list li:last-child {
  margin-bottom: 2rem;
}
.wrapper .accordion .panel .acc-body ol.custom-list li a {
  color: #005fec;
}
.wrapper .accordion .panel .acc-body ol.custom-list li a:hover {
  text-decoration: underline;
  -webkit-text-decoration-color: #005fec;
          text-decoration-color: #005fec;
}
.wrapper .accordion .panel .acc-body ul.custom-list {
  list-style-type: none;
  -webkit-margin-before: 0;
  margin-block-start: 0;
  -webkit-margin-after: 0;
  margin-block-end: 0;
}
.wrapper .accordion .panel .acc-body ul.custom-list li {
  background-image: url(/assets/svg/bullet.svg);
  background-position: 0 0.5rem;
  background-repeat: no-repeat;
  padding-left: 1.125rem;
  margin: 2rem 0;
  font-size: 1rem;
  line-height: 1.5rem;
}
.wrapper .accordion .panel .acc-body ul.custom-list li a {
  color: #005fec;
}
.wrapper .accordion .panel .acc-body ul.custom-list li a:hover {
  text-decoration: underline;
  -webkit-text-decoration-color: #005fec;
          text-decoration-color: #005fec;
}
.wrapper .accordion .panel .acc-body ul.custom-list li:first-child {
  margin-top: 0;
}
.wrapper .accordion .panel .acc-body ul.custom-list li:last-child {
  margin-bottom: 2rem;
}
.wrapper .accordion .panel + .panel {
  margin-top: 1rem;
}
.wrapper .accordion .panel.active .acc-body {
  opacity: 1;
  height: auto;
  padding: 0.5rem 0;
  visibility: visible;
}
.wrapper .accordion .panel.active .acc-body p {
  font-size: 1rem;
  line-height: 1.5rem;
}
.wrapper .accordion .panel.active .acc-body p + .embed-youtube {
  margin: 1rem 0;
}
.wrapper .accordion .panel.active .acc-body p a {
  color: #005fec;
}
.wrapper .accordion .panel.active .acc-body p a:hover {
  text-decoration: underline;
  -webkit-text-decoration-color: #005fec;
          text-decoration-color: #005fec;
}
.wrapper .accordion .panel.active .acc-icon {
  transform: rotate(180deg);
}
.wrapper .accordion .panel.active .acc-trigger .acc-title {
  border-bottom: 0;
}
.wrapper .accordion .panel.active p:last-child {
  padding-bottom: 0.5rem;
}

.acc-title svg.acc-icon {
  transition: all 1s ease;
  min-width: 1rem;
}

@media (min-width: 768px) {
  .wrapper {
    flex-direction: row;
  }

  .accordion {
    flex: 1;
  }
}
<section id="questions">
  <div class="container">
    <div class="row justify-content-center align-items-start">
      <h3>Any Questions?</h3>
      <div class="wrapper">
        <div class="accordion">
          <div class="panel">
            <button class="acc-trigger">
                <span class="acc-title">
                  <h4>Lorem ipsum dolor sit amet.</h4>
                  <svg class="acc-icon" width="16" height="11" viewBox="0 0 16 11" fill="none"
                    xmlns="http://www.w3.org/2000/svg">
                    <path d="M0 2.82813L2 0.828126L8 6.82813L14 0.828126L16 2.82813L8 10.8281L0 2.82813Z"
                      fill="#000A70" />
                  </svg>
                </span>
              </button>
            <div class="acc-body">
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
            </div>
          </div>
          <div class="panel">
            <button class="acc-trigger">
                <span class="acc-title">
                  <h4>Lorem ipsum dolor sit amet.</h4>
                  <svg class="acc-icon" width="16" height="11" viewBox="0 0 16 11" fill="none"
                    xmlns="http://www.w3.org/2000/svg">
                    <path d="M0 2.82813L2 0.828126L8 6.82813L14 0.828126L16 2.82813L8 10.8281L0 2.82813Z"
                      fill="#000A70" />
                  </svg>
                </span>
              </button>
            <div class="acc-body">
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
              <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi enim quas laboriosam itaque harum ab voluptas? Deserunt aliquam pariatur voluptatem odit iure autem eos totam eius consequuntur animi. Omnis, ipsam.</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>


from How to use JavaScript to apply slidedown functionality in accordion?

No comments:

Post a Comment