Skip to content
Advertisement

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>

Advertisement

Answer

Since you can’t transition/animate between height:0px and auto you might try this approach:

We’re hiding all accordion contents on load in a way that still allows us to calculate their individual heights by js.

.acc-body {
    position: absolute;
    height: auto;
} 

We can now store these height values as a data-attribute added to each accordion body.
When a accordion section gets expanded, this height value is applied as a max-height inline-style.

Example 1: Accordion

// get acc heights
let accordionContents = document.querySelectorAll('.acc-body');
getAccordionHeights(accordionContents);

function getAccordionHeights(accordionContents) {
  accordionContents.forEach(function(acc, i) {
    // reset heights on resize
    if (acc.classList.contains('acc-body-init')) {
      acc.removeAttribute('style');
      acc.classList.remove('acc-body-init');
      console.log('acc heights recalculated')
    }
    let bb = acc.getBoundingClientRect();
    let h = bb.height;
    acc.setAttribute('data-height', (h * 1.5) + 'px');
    acc.classList.add('acc-body-init');
  })
}

// add click event handlers
let accTriggers = document.querySelectorAll('.acc-trigger');
accTriggers.forEach(function(btn, i) {
  btn.addEventListener('click', function(e) {
    let panel = e.currentTarget.closest('.panel');
    let btn = panel.querySelector('.acc-trigger');
    let acc = panel.querySelector('.acc-body');
    let accHeight = acc.getAttribute('data-height');
    let opened = document.querySelectorAll('.active');
    // toggle this btn state
    panel.classList.toggle('active');
    // apply max-height from data-attribute
    if (panel.classList.contains('active')) {
      acc.style.maxHeight = accHeight;
      btn.setAttribute('aria-expanded', 'true');
      acc.setAttribute('aria-hidden', 'false');
    } else {
      acc.style.maxHeight = '0px';
      btn.setAttribute('aria-expanded', 'false');
      acc.setAttribute('aria-hidden', 'true');
    }
    if (!isWideScreen()) {
      closeOpened(opened)
    }

  })
});

// add close all previously opened
function closeOpened(opened) {
  opened.forEach(function(panel, i) {
    let acc = panel.querySelector('.acc-body');
    let btn = panel.querySelector('.acc-trigger');
    panel.classList.remove('active');
    acc.style.maxHeight = '0px';
    btn.setAttribute('aria-expanded', 'false');
    acc.setAttribute('aria-hidden', 'true');
  });
}

let isWideScreen = () => {
  return window.matchMedia("(min-width: 992px)").matches;
};

// recalculate heights on window resize
window.onresize = function(e) {
  let opened = document.querySelectorAll('.active');
  getAccordionHeights(accordionContents);
  closeOpened(opened)
}
.acc-icon {
  display: inline-block;
  height: 1em;
}

.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;
}

.panel {
  margin: 0;
  border-bottom: 1px solid #000A70;
  overflow: hidden;
  position: relative;
}

.acc-trigger {
  display: flex;
  align-items: center;
  outline: 0;
  padding-bottom: 0.5rem;
  font-weight: 400;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: left;
  width: 100%;
  cursor: pointer;
  background: 0 0;
  padding: 1em 0;
}

.acc-icon {
  color: inherit;
  pointer-events: none;
  margin-left: auto;
  z-index: 3;
  transition: all 1s ease;
  align-self: flex-start;
  padding: 0.5em 0;
  width: 1em;
  height: 1em;
  font-size: 1.2em;
}

.acc-trigger h4 {
  font-weight: 800;
  font-size: 1.25rem;
  outline: 0;
  padding: 0;
  margin: 0;
  margin-right: 1rem;
}

.acc-trigger:focus,
.acc-trigger:hover {
  color: #005fec;
}


/*** hidden acc body before initialisation to get heights */

.acc-body {
  position: absolute;
  height: auto;
  visibility: hidden;
  clip: rect(0px auto 2px 0px);
  font-size: 1rem;
  line-height: 1.5rem;
  padding: 0.5rem 0;
}

.acc-body-init {
  position: relative;
  overflow: hidden;
  max-height: 0px;
  clip: unset;
  transition: all 0.5s ease-out;
}

.active .acc-body-init {
  max-height: 500px;
  padding-bottom: 1em;
  visibility: visible;
}

.acc-body p a {
  color: #005fec;
}

.acc-body p a:hover {
  text-decoration: underline;
  -webkit-text-decoration-color: #005fec;
  text-decoration-color: #005fec;
}

.active .acc-icon {
  transform: rotate(180deg);
}

.active .acc-trigger {
  border-bottom-color: transparent;
}

.panel p:last-child {
  padding-bottom: 0.5rem;
}

@media (min-width: 768px) {
  .wrapper {
    flex-direction: row;
  }
  .accordion {
    flex: 1;
  }
}
<svg style="display:none" class="acc-icon" width="16" height="11" viewBox="0 0 16 11" fill="none" xmlns="http://www.w3.org/2000/svg">
    <symbol id="btn-acc" viewBox="0 0 16 11">
        <path d="M0 2.82813L2 0.828126L8 6.82813L14 0.828126L16 2.82813L8 10.8281L0 2.82813Z" fill="currentColor" />
    </symbol>
</svg>

<section id="questions">
  <div class="wrapper">
    <div class="accordion">
      <div class="panel">
        <button class="acc-trigger" aria-expanded="false" id="accBtn01">
                        <h4>Lorem ipsum dolor sit amet.</h4>
                        <svg class="acc-icon" viewBox="0 0 16 11"  >
                          <use href="#btn-acc"/>
                        </svg>
                    </button>
        <div class="acc-body" aria-hidden="true" aria-labelledby="accBtn01">
          <p>Lorem ipsum dolor sit amet, <a href="#">consectetur</a> 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>
          <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" aria-expanded="false" id="accBtn02">
                        <h4>Lorem ipsum dolor sit amet. <br />Lorem ipsum dolor sit amet. </h4>
                        <svg class="acc-icon" viewBox="0 0 16 11" >
                            <use href="#btn-acc"/>
                          </svg>
                    </button>
        <div class="acc-body" aria-hidden="true" aria-labelledby="accBtn02">
          <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>

</section>

You might also need a window resize event handler to recalculate heights, when the window resizing occurs.

I also strongly recommend to add appropriate aria-attributes for better accessibility.

Example 2: height checking on click

// add click event handlers
const selectorPanel = '.panel';
const selectorTrigger = '.acc-trigger';
const selectorAccContent = '.acc-body';
let accTriggers = document.querySelectorAll(selectorTrigger);
let accordionContents = document.querySelectorAll(selectorAccContent);
let panels = document.querySelectorAll(selectorPanel);

// add aria attributes
autoAriaAttributes(panels);
function autoAriaAttributes(panels){
    panels.forEach(function (panel, i) {
        let trigger = panel.querySelector(selectorTrigger);
        let acc = panel.querySelector(selectorAccContent);
        trigger.setAttribute('aria-expanded', 'false');
        if(!trigger.id){
            trigger.id = 'accTrigger-'+i;
        }
        trigger.setAttribute('aria-expanded', 'false');
        acc.setAttribute('aria-labelledby', trigger.id );
        acc.setAttribute('aria-hidden', 'true' );
    });
}

accTriggers.forEach(function (btn, i) {
    btn.addEventListener('click', function (e) {
        let panel = e.currentTarget.closest(selectorPanel);
        let btn = panel.querySelector(selectorTrigger);
        let acc = panel.querySelector(selectorAccContent);

        let opened = document.querySelectorAll('.active');
        // toggle this btn state
        panel.classList.toggle('active');
        let accHeight = acc.scrollHeight * 1.5;

        // apply max-height from data-attribute
        if (panel.classList.contains('active')) {
            acc.style.maxHeight = accHeight+'px';
            btn.setAttribute('aria-expanded', 'true');
            acc.setAttribute('aria-hidden', 'false');

        }else{
            acc.style.maxHeight = null;
            btn.setAttribute('aria-expanded', 'false');
            acc.setAttribute('aria-hidden', 'true');
        }
        if(!isWideScreen() ){
            closeOpened(opened)
        }
    })
});

// add close all previously opened
function closeOpened(opened) {
        opened.forEach(function (panel, i) {
            let acc = panel.querySelector(selectorAccContent);
            let btn = panel.querySelector(selectorTrigger);
            panel.classList.remove('active');
            acc.style.maxHeight = null;
            btn.setAttribute('aria-expanded', 'false');
            acc.setAttribute('aria-hidden', 'true');
        });
}

let isWideScreen = () => {
    return window.matchMedia("(min-width: 992px)").matches;
};

// recalculate heights on window resize
window.onresize = function(e) {
  let opened = document.querySelectorAll('.active');
  closeOpened(opened)
}
.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;
}

.acc-trigger {
  display: flex;
  align-items: center;
  outline: 0;
  padding-bottom: 0.5rem;
  font-weight: 400;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: left;
  width: 100%;
  cursor: pointer;
  background: 0 0;
  padding: 1em 0;
}

.acc-icon {
  display: inline-block;
  color: inherit;
  pointer-events: none;
  margin-left: auto;
  z-index: 3;
  transition: all 1s ease;
  align-self: flex-start;
  padding: 0.5em 0;
  width: 1em;
  height: 1em;
  font-size: 1.2em;
}

.acc-trigger h4 {
  font-weight: 800;
  font-size: 1.25rem;
  outline: 0;
  padding: 0;
  margin: 0;
  margin-right: 1rem;
}

.acc-trigger:focus,
.acc-trigger:hover {
  color: #005fec;
}

.panel {
  margin: 0;
  border-bottom: 1px solid #000A70;
  overflow: hidden;
}


/**
* hidden acc body before initialisation to get heights 
* visibility is set to hidden 
* to prevent invisible elements from being focused
*/

.acc-body {
  position: relative;
  overflow: hidden;
  visibility: hidden;
  max-height: 0px;
  transition-property: max-height, visibility;
  transition-delay: 0s;
  transition-duration: 0.5s;
  transition-timing-function: ease-out, ease-out;
  padding: 0.5rem 0;
}

.active .acc-body {
  padding-bottom: 2em;
  visibility: visible;
  overflow: visible;
}

.acc-body p a {
  color: #005fec;
}

.acc-body p a:hover {
  text-decoration: underline;
  -webkit-text-decoration-color: #005fec;
  text-decoration-color: #005fec;
}

.active .acc-icon {
  transform: rotate(180deg);
}

.active .acc-trigger {
  border-bottom-color: transparent;
}

.panel p:last-child {
  padding-bottom: 0.5rem;
}

@media (min-width: 768px) {
  .wrapper {
    flex-direction: row;
  }
  .accordion {
    flex: 1;
  }
}
<style>
  body {
    font-size: 2em;
    line-height: 2em;
  }
  
  .resizable {
    overflow: auto;
    resize: both;
    border: 1px solid #ccc;
    padding: 1em;
  }
  
  #questions {
    width: 800px;
    max-width: 90%;
    margin: 0 auto;
  }
</style>

<!-- fallback if js disabled -->
<noscript>
        <style>
            .acc-body {
                padding-bottom: 2em;
                visibility: visible;
                overflow: visible;
                max-height:inherit;
            }
        </style>
</noscript>

<svg style="display:none" class="acc-icon" width="16" height="11" viewBox="0 0 16 11" fill="none" xmlns="http://www.w3.org/2000/svg">
    <symbol id="btn-acc" viewBox="0 0 16 11">
        <path d="M0 2.82813L2 0.828126L8 6.82813L14 0.828126L16 2.82813L8 10.8281L0 2.82813Z" fill="currentColor" />
    </symbol>
</svg>

<section class="resizable" id="questions">
    <div class="wrapper">
        <div class="accordion">
            <div class="panel">
                <button class="acc-trigger">
                    <h4>Lorem ipsum dolor sit amet.</h4>
                    <svg class="acc-icon" viewBox="0 0 16 11">
                        <use href="#btn-acc" />
                    </svg>
                </button>
                <div class="acc-body" style="color:#777">
                    <p>Lorem ipsum dolor sit amet, <a href="#">focusable link</a> 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>
                    <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. <strong>Last</strong></p>
                </div>
            </div>
            <div class="panel">
                <button class="acc-trigger">
                    <h4>Lorem ipsum dolor sit amet. <br />Lorem ipsum dolor sit amet. </h4>
                    <svg class="acc-icon" viewBox="0 0 16 11">
                        <use href="#btn-acc" />
                    </svg>
                </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. <strong>Last</strong></p>
                </div>
            </div>
        </div>
    </div>
</section>

Edits:
To improve accessibility, collapsed accordion have visibility set to hidden to prevent hidden elements from getting focus (try to navigate via Tab key).
Basic ARIA attributes for visibility states can be added automatically.

This snippet will calculate the necessary max-height values on click via element.scrollHeight
Be careful: due to reflows this value might change after exapanding the accordion – therefore you might need some additional height like
let accHeight = acc.scrollHeight * 1.5;

There is also a “no-js” fallback to ensure all content is displayed, when js is disabled.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement