Millhorn
Millhorn

Reputation: 3176

How to rotate an SVG icon 180° when accordion is open?

I'm struggling to rotate an icon in this accordion when the accordion is open. I've done most of the work, but I'm missing something.

How do I rotate the SVG icon by 180deg when it's open? And then back to its origin when closed?

If you'd prefer a Codepen, it is here.

This is the snippet I'm using to rotate the icon.

[...document.querySelectorAll('.acc-icon')].forEach(function(item) {
  item.addEventListener('click', function() {
    this.classList.toggle('down');
  })
})

function initAccordion() {
  function handlePanelClick(event) {
    showPanel(event.currentTarget);
  }

  function showPanel(panelHeader) {
    let isActive,
      panel = panelHeader.parentNode,
      expandedPanel = document.querySelector(".panel.active");

    isActive =
      expandedPanel && panel.classList.contains("active") ? true : false;

    if (expandedPanel) {
      expandedPanel.querySelector(".acc-body").style.height = null;
      expandedPanel.classList.remove("active");
    }

    if (panel && !isActive) {
      panel.classList.add("active");
    }
  }

  let allPanelElements = document.querySelectorAll(".panel");

  for (let i = 0; i < allPanelElements.length; i++) {
    allPanelElements[i]
      .querySelector(".acc-trigger")
      .addEventListener("click", handlePanelClick);
  }

  showPanel(allPanelElements);
}

[...document.querySelectorAll('.acc-icon')].forEach(function(item) {
  item.addEventListener('click', function() {
    this.classList.toggle('down');
  })
})

initAccordion(document.getElementsByClassName("accordion"));
.wrapper {
  margin: 50px auto;
  display: flex;
  flex-direction: column
}

.wrapper a {
  text-decoration: none
}

.wrapper button {
  border-style: none;
  background: #fff
}

.wrapper button::-moz-focus-inner {
  border: 0
}

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

  .accordion {
    flex: 1
  }
}

.wrapper .accordion {
  margin: 0 .1rem
}

.wrapper .accordion .panel {
  min-height: 4rem;
  margin: 0 .1rem
}

.wrapper .accordion .panel .acc-trigger {
  display: block;
  font-weight: 400;
  margin: 0;
  padding: .5em 1em;
  position: relative;
  text-align: left;
  width: 100%;
  cursor: pointer;
  background: 0 0
}

.wrapper .accordion .panel .acc-trigger .acc-title {
  display: flex;
  align-items: center;
  border: transparent 2px solid;
  outline: 0
}

.wrapper .accordion .panel .acc-trigger .acc-title h4 {
  font-weight: 600;
  color: #000a70;
  font-size: 1.25rem;
  justify-content: space-between;
  margin-right: 1rem;
  outline: 0
}

.wrapper .accordion .panel .acc-trigger .acc-title svg.acc-icon {
  cursor: pointer;
  pointer-events: none;
  margin-left: auto;
  z-index: 3;
}



.acc-title svg.acc-icon {
  transition: all 0.2s ease-in-out;
}

.acc-title svg.acc-icon.down {
  transform: rotate(180deg);
}

.wrapper .accordion .panel .acc-body {
  height: 0;
  opacity: 0;
  overflow: hidden;
  visibility: hidden;
  transition: height .2s ease-out, opacity .2s ease-out;
}


.wrapper .accordion .panel.active .acc-body p {
  font-size: 16px;
  line-height: 24px;
  margin-bottom: 24px;
}

.wrapper .accordion .panel.active .acc-body p a {
  color: #005fec;
}

.wrapper .accordion .panel.active .acc-body p a:hover {
  text-decoration: underline;
  text-decoration-color: #005fec;
}

.wrapper .accordion .panel.active .acc-body p a:hover {
  text-decoration: underline;
  text-decoration-color: #005fec;
}

.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,
.wrapper .accordion .panel .acc-body ul.custom-list li a {
  color: #005fec
}

.wrapper .accordion .panel .acc-body ol.custom-list li a:hover,
.wrapper .accordion .panel .acc-body ul.custom-list li a:hover {
  text-decoration: underline;
  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 .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:first-child {
  margin-top: 0
}

.wrapper .accordion .panel .acc-body ul.custom-list li:last-child {
  margin-bottom: 2rem;
}

.wrapper .accordion .panel.active .acc-body {
  opacity: 1;
  height: auto;
  padding: .5rem 1rem;
  visibility: visible
}

.wrapper .accordion .panel .acc-trigger .acc-title {
  border-bottom: 1px solid #000a70;
  padding-bottom: .5rem;
  transition: all .2s ease;
}

.wrapper .accordion .panel.active .acc-trigger .acc-title {
  border-bottom: 0;
}

.wrapper .accordion .panel.active p:last-child {
  border-bottom: 1px solid #000a70;
  padding-bottom: .5rem
}

.wrapper .accordion .panel .acc-trigger .acc-title h4:hover,
.wrapper .accordion .panel.active .acc-trigger .acc-title h4 {
  color: #005fec
}
<div class="wrapper">
  <div class="accordion">
    <div class="panel">
      <button aria-expanded="false" class="acc-trigger">
        <span class="acc-title">
          <h4>Question One</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. Saepe harum eaque quis, unde neque quo minima porro praesentium cum id.</p>
        <p>Doloremque facere deserunt dolore minus repellat. Quas impedit nihil, deserunt a laboriosam animi ullam quidem earum commodi, rerum assumenda incidunt.</p>
        <p>Quo nihil beatae pariatur. Porro vitae eius hic harum aliquam asperiores voluptatem assumenda, iure quae maiores quis possimus error itaque!</p>
      </div>
    </div>
    <div class="panel">
      <button aria-expanded="false" class="acc-trigger">
        <span class="acc-title">
          <h4>Question Two</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. Saepe harum eaque quis, unde neque quo minima porro praesentium cum id.</p>
        <p>Doloremque facere deserunt dolore minus repellat. Quas impedit nihil, deserunt a laboriosam animi ullam quidem earum commodi, rerum assumenda incidunt.</p>
        <p>Quo nihil beatae pariatur. Porro vitae eius hic harum aliquam asperiores voluptatem assumenda, iure quae maiores quis possimus error itaque!</p>
      </div>
    </div>    
  </div>
</div>

Upvotes: 0

Views: 179

Answers (1)

JBaczuk
JBaczuk

Reputation: 14629

You can get the svg from the clicked panel and rotate it using a css transform: rotate

function initAccordion() {
  function handlePanelClick(event) {
    showPanel(event.currentTarget);
  }

  function showPanel(panelHeader) {
    let isActive,
      panel = panelHeader.parentNode,
      expandedPanel = document.querySelector(".panel.active");

    isActive =
      expandedPanel && panel.classList.contains("active") ? true : false;

    if (expandedPanel) {
      expandedPanel.querySelector(".acc-body").style.height = null;
      expandedPanel.classList.remove("active");
      const svg = panel.querySelector("svg");
      svg.style.transform = 'rotate(0deg)'
    }

    if (panel && !isActive) {
      panel.classList.add("active");
      const svg = panel.querySelector("svg");
      svg.style.transform = 'rotate(180deg)'
    }
  }

  let allPanelElements = document.querySelectorAll(".panel");

  for (let i = 0; i < allPanelElements.length; i++) {
    allPanelElements[i]
      .querySelector(".acc-trigger")
      .addEventListener("click", handlePanelClick);
  }

  showPanel(allPanelElements);
}

[...document.querySelectorAll('.acc-icon')].forEach(function(item) {
  item.addEventListener('click', function() {
    this.classList.toggle('down');
  })
})

initAccordion(document.getElementsByClassName("accordion"));
.wrapper {
  margin: 50px auto;
  display: flex;
  flex-direction: column
}

.wrapper a {
  text-decoration: none
}

.wrapper button {
  border-style: none;
  background: #fff
}

.wrapper button::-moz-focus-inner {
  border: 0
}

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

  .accordion {
    flex: 1
  }
}

.wrapper .accordion {
  margin: 0 .1rem
}

.wrapper .accordion .panel {
  min-height: 4rem;
  margin: 0 .1rem
}

.wrapper .accordion .panel .acc-trigger {
  display: block;
  font-weight: 400;
  margin: 0;
  padding: .5em 1em;
  position: relative;
  text-align: left;
  width: 100%;
  cursor: pointer;
  background: 0 0
}

.wrapper .accordion .panel .acc-trigger .acc-title {
  display: flex;
  align-items: center;
  border: transparent 2px solid;
  outline: 0
}

.wrapper .accordion .panel .acc-trigger .acc-title h4 {
  font-weight: 600;
  color: #000a70;
  font-size: 1.25rem;
  justify-content: space-between;
  margin-right: 1rem;
  outline: 0
}

.wrapper .accordion .panel .acc-trigger .acc-title svg.acc-icon {
  cursor: pointer;
  pointer-events: none;
  margin-left: auto;
  z-index: 3;
}



.acc-title svg.acc-icon {
  transition: all 0.2s ease-in-out;
}

.acc-title svg.acc-icon.down {
  transform: rotate(180deg);
}

.wrapper .accordion .panel .acc-body {
  height: 0;
  opacity: 0;
  overflow: hidden;
  visibility: hidden;
  transition: height .2s ease-out, opacity .2s ease-out;
}


.wrapper .accordion .panel.active .acc-body p {
  font-size: 16px;
  line-height: 24px;
  margin-bottom: 24px;
}

.wrapper .accordion .panel.active .acc-body p a {
  color: #005fec;
}

.wrapper .accordion .panel.active .acc-body p a:hover {
  text-decoration: underline;
  text-decoration-color: #005fec;
}

.wrapper .accordion .panel.active .acc-body p a:hover {
  text-decoration: underline;
  text-decoration-color: #005fec;
}

.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,
.wrapper .accordion .panel .acc-body ul.custom-list li a {
  color: #005fec
}

.wrapper .accordion .panel .acc-body ol.custom-list li a:hover,
.wrapper .accordion .panel .acc-body ul.custom-list li a:hover {
  text-decoration: underline;
  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 .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:first-child {
  margin-top: 0
}

.wrapper .accordion .panel .acc-body ul.custom-list li:last-child {
  margin-bottom: 2rem;
}

.wrapper .accordion .panel.active .acc-body {
  opacity: 1;
  height: auto;
  padding: .5rem 1rem;
  visibility: visible
}

.wrapper .accordion .panel .acc-trigger .acc-title {
  border-bottom: 1px solid #000a70;
  padding-bottom: .5rem;
  transition: all .2s ease;
}

.wrapper .accordion .panel.active .acc-trigger .acc-title {
  border-bottom: 0;
}

.wrapper .accordion .panel.active p:last-child {
  border-bottom: 1px solid #000a70;
  padding-bottom: .5rem
}

.wrapper .accordion .panel .acc-trigger .acc-title h4:hover,
.wrapper .accordion .panel.active .acc-trigger .acc-title h4 {
  color: #005fec
}
<div class="wrapper">
  <div class="accordion">
    <div class="panel">
      <button aria-expanded="false" class="acc-trigger">
        <span class="acc-title">
          <h4>Question One</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. Saepe harum eaque quis, unde neque quo minima porro praesentium cum id.</p>
        <p>Doloremque facere deserunt dolore minus repellat. Quas impedit nihil, deserunt a laboriosam animi ullam quidem earum commodi, rerum assumenda incidunt.</p>
        <p>Quo nihil beatae pariatur. Porro vitae eius hic harum aliquam asperiores voluptatem assumenda, iure quae maiores quis possimus error itaque!</p>
      </div>
    </div>
    <div class="panel">
      <button aria-expanded="false" class="acc-trigger">
        <span class="acc-title">
          <h4>Question Two</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. Saepe harum eaque quis, unde neque quo minima porro praesentium cum id.</p>
        <p>Doloremque facere deserunt dolore minus repellat. Quas impedit nihil, deserunt a laboriosam animi ullam quidem earum commodi, rerum assumenda incidunt.</p>
        <p>Quo nihil beatae pariatur. Porro vitae eius hic harum aliquam asperiores voluptatem assumenda, iure quae maiores quis possimus error itaque!</p>
      </div>
    </div>    
  </div>
</div>

Upvotes: 1

Related Questions