Accordion Component for VueJS and GSAP
Tags: codepen, vue, design, showdev
Published: 2019-08-12 13:48:20

<p>Accordion component, written in VueJS. The animations are done with GSAP.</p>

---

# How it works

<p>Let's just style an accordion on however you want it. You may make it colourful, or simple.</p>

<p>The only difference is the caret. I did not do it like how you commonly do the triangle thing by CSS. I tried to make my own (ugly, and for modern browsers only) way.</p>

```css
.accordion-caret {
  background-image: linear-gradient(to top right, transparent 50%, #727272 50%);
  width: 0.5rem;
  height: 0.5rem;
  transform: rotate(-45deg);
}
```

<p>I don't know, but it was more comfortable for me to style, than do the traditional way to do the triangle. Also, well, I want a little change.</p>

* Disclaimer: Note that I am pretty sure that there is someone who already did that way. It's just like I am not actually browsing the internet to get a code, to do all of these (except for the documentation for each libraries/frameworks which I browse the official documentation).

### The Vue VM

<p>Because I can't put a real-world data on my pen, I just put a static data to be supplied. It must be placed on the VM.</p>

```javascript
var app = new Vue({
  el: '#app',
  data: {
    // 'title' is for the header. The area that you can see.
    // 'description' is for the content. It will show after you expand an accordion menu
    // 'active' is for the flag, if the content is shown or not.
    contents: [{
      title: 'Lorem ipsum dolor sit amet',
      description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
      active: false
    }, {
      title: 'Ut enim ad minim veniam',
      description: 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
      active: false
    } // ...
    ]
  }
});
```

### Template

<p>I just looped the passed props from the VM to the component, to display the template or the design of the accordion.</p>

```html
<div class="accordion">
  <!-- Looping of the props. -->
  <div
    class="accordion-item"
    v-for="content, i in contents"
    v-bind:class="{ 'accordion-active': content.active }"
  >
    <div class="accordion-header">
      <!-- The click event of each accordion menu -->
      <a href="#" v-on:click="expand(event, i)">
        <div class="accordion-header-div">{{ content.title }}</div>
        <div class="accordion-header-div">
          <div class="accordion-caret"></div>
        </div>
      </a>
    </div>
    <!-- We need the ref to get the DOM of the body. -->
    <div class="accordion-body" v-bind:ref="'accordion-body-' + i">
      <div class="accordion-content">{{ content.description }}</div>
    </div>
  </div>
</div>
```

* I used the HTML highlighting so that the element may be comprehended easily. Also, because there is also an other way to write our template.

### Animation for the expansion

<p>Below is how you do the expansion. Basically, I used GSAP to do akk the works in animation. Honestly, it is easier to use, than the CSS animation. Also, its transition is better than the native CSS transition.</p>

```javascript
// The dom of the accordion body, we will bind the GSAP animation here
let el = this.$refs['accordion-body-' + i][0];

if (this.contents[i].active === false) {
  this.contents[i].active = true;

  // The GSAP animation for the expansion of an accordion menu
  TweenLite.to(el, 1, {
    height: el.scrollHeight,
    ease: Elastic.easeOut.config(1, 0.3)
  });
} else {
  this.contents[i].active = false;

  // The GSAP animation to hide the accordion menu content
  TweenLite.to(el, 0.5, {
    height: 0,
    ease: Bounce.easeOut
  });
}
```

* To read more about GSAP, you may follow this link: [Greensock](https://greensock.com/docs/)

* VueJS documentation: [VueJS Guide](https://vuejs.org/v2/guide/)
* Addition: Yes, the guide itself is really comprehensible, that when you read it, you can actually use VueJS, comfortably.

---

# Demo

{% codepen https://codepen.io/takaneichinose/pen/rXMrgv %}