Build a Counter, Dropdown and Accordion in Vue Components! blog post

Build a Counter, Dropdown and Accordion in Vue Components!

Debbie O'Brien

21 Aug, 2019

Vue

8 minutes read

Counter

Let’s dive into building some core main components that you might be tasked with when writing applications in Vue. Or, if you’re new to Vue, then these are definitely some great ways to get started understanding the more ‘common’ components that we might work with on a day-to-day basis. With that in mind, let’s get started right away with building a Counter, Dropdown and finally an Accordion with Vue!

In Vue we can use the v-on directive to listen to DOM events and run some JavaScript when they’re triggered. The shorthand version of v-on: is @. For example we could write a directive for a click event like this v-on:click which will work exactly the same as writing @click.

A simple example of a click event would be to add a person to a booking. We can create a button with a click directive and add some logic which in this case is adult is equal to adult plus 1. So every time we click the button the value of adult will increment by 1. We can then use the double moustaches to print the value of adult. {{ adult }}.

<template>
  <div>
    <span>Adult</span>
    <button>+</button>
    <p>{{ adult }} adults</p>
  </div>
</template>

But of course first we have to set the value of adult otherwise the button doesn’t know what to add 1 to. We do that by adding it to the data of our component and setting its value to 0.

export default {
  data() {
    return {
      adult: 0,
    }
  }
}

And just as easily we can create a minus button to remove all those adults that we just added.

<button @click="adult -= 1">-</button>

But it is not always a good idea to add the logic direct into our click event as most of the time the logic is more complex than just a simple add and minus. For this we use methods and we can easily pass in the name of a method instead of our logic. We can simply name our methods minusAdult and addAdult. Every time an event occurs, that method is called.

<template>
  <div>
    <button @click="minusAdult">-</button>
    <span>Adult</span>
    <button @click="addAdult">+</button>
    <p>{{ adult }} adults</p>
  </div>
</template>

We now define our methods under the methods object. The first method we have is addAdult which is a function. Inside the function we add our logic as we did above but this time, the only difference is, we need to add the this keyword which allows us to access any of the data properties. this.adult refers to the adult property in our data.

export default {
  data() {
    return {
      adult: 0,
    };
  },
  methods: {
    addAdult() {
      this.adult += 1;
    },
    minusAdult() {
      this.adult -= 1;
    }
  }
}

Now everything works just like before but this time all our logic is in our methods which also makes it easier to work with and modify than having it direct in the code.

Check out the live project:

Dropdown Component

Let’s make a simple dropdown component. All we need is a button and a div with a list inside it.

<template>
  <div>
    <button>Dropdown</button>
    <div>
      <ul>
        <li>Nuxt</li>
        <li>Vue</li>
        <li>Webpack</li>
      </ul>
    </div>
  </div>
</template>

In order for our button to work we need to add a click directive and tell it what to do when we click it. We want it to show the div and when we click it again we want it to hide the div. Basically we want to toggle it so let’s call our method toggle.

<button @click="toggle">Click Me</button>

What we want to toggle is the div so in order to do that we need to use the v-show directive. We want it to show only when we click the button. Let’s create a data property called isOpen and set it to false. We can then add this value to our v-show directive so basically only show when isOpen is true.

export default {
  data() {
    return {
      isOpen: false
    };
  }
};

Now you will see that our list is not visible as the value of isOpen is set to false. In order to make it true we need to create our toggle method that will toggle that value between true and false. We do this by making our data property isOpen equal to the opposite of its value. this.isOpen = !this.isOpen which basically means if the value is false make it true and if it is true make it false. so every time we click our button we trigger the toggle method which makes our value of isOpen true or false and when the value is true our div appears.

methods: {
  toggle() {
    this.isOpen = !this.isOpen;
  }
}

Check out the live project:

Accordion Component

An accordion component works very similar to the dropdown component. But if we were to copy what we did in the dropdown component then it would not work as expected as if you clicked on any of the titles all the accordions would open. We want only the one we click on to actually open and close. We could of course create a toggle method for each one but there is an easier way of doing it and that is by using slots.

First we create a parent component for our Accordion which we will call BaseAccordion. This is very similar to the dropdown component in that we add a @click method to the div with the value of toggle and a v-show directive with the value of show. The only difference is that instead of adding the content we add a slot. As we have 2 slots, one for the title and one for the content we shall used named slots. That way it will be easier to define which one is which when we go to use it.

<template>
  <div class="wrapper">
    <div class="accordion" @click="toggle">
      <h2 class="title">
        <slot name="title"></slot>
      </h2>
    </div>
    <div v-show="show" class="content">
      <slot name="content"></slot>
    </div>
  </div>
</template> 

Then in our script tag just like before we need to add a data property of show with the value of false as we don’t want to show it until it is clicked and a toggle method that toggles the value so that every time the toggle method is activated true becomes false or false becomes true.

export default {
  components: {},
  data() {
    return {
      show: false,
    };
  },
  methods: {
    toggle() {
      this.show = !this.show;
    },
  }
}

We now need to use this accordion in our component. What we have created is a base component that can then be used in many places as we could have various accordions on our site. Let’s create a Tech Accordion component that will then use the Base Accordion. To do this we need to import the BaseAccordion.

import BaseAccordion from '@/components/_base-accordion';

export default {
  components: {
    BaseAccordion,
  }
};

And in our template we can use the v-for directive so that for every accordion in the accordions array we will print a BaseAccordion component. The difference with this component is that we use the template tag inside it to make reference to the slot we want to use by using the v-slot directive. And then inside the template we add the information we want to show which in our case is the title of the accordion from the accordions array. We do the same for the content slot and as you can see we want to use a div inside the slot which is also possible.

<template>
  <div>
    <div>
      {{ accordion.title }}
      <div>
        {{ accordion.text }}
      </div>
    </template>
      </BaseAccordion>
    </div>
  </div>
</template>

Now we just have to create our array of content for our accordion. We do this by adding a property to our data called accordions and adding an array with different values. We can add as many as we want here and the v-for will print out an accordion for every entry we have.


export default {
  data() {
    return {
      accordions: [
        {
          title: 'Vue',
          text: 'All about Vue',
        },
        {
          title: 'Nuxt',
          text: 'All about Nuxt',
        },
        {
          title: 'webpack',
          text: 'All about webpack',
        },
      ],
    }
  }
}

Check out the live project:

And that’s it we now have a fully working Counter, Dropdown and Accordion component using Vue’s directives and methods. I hope you have fun making some really cool components.

About the author

Debbie works as a Frontend Tech Lead at Patterson Agency, a digital agency in Mallorca, Spain. With over 10 years experience in Frontend development she has a special love for JavaScript frameworks especially Vue.JS and Nuxt.js and improving performance with webpack. Debbie holds a Frontend and FullStack Tech Degree and is Microsoft certified. She is an international speaker and organiser of MallorcaJS and VueSpain. She also works as a tech degree moderator for Treehouse and a mentor for OpenClassrooms and is a webpack and Nuxt.js contributor. She is a teacher at Vue School and a writer for Ultimate Courses. When she is not programming she loves doing sport - Taekwondo, Skiing, Cycling, Running..

Love the post? Share it!

Lots of time and effort go into all our blogs, resources and demos,
we'd love it if you'd spare a moment to share them!

Explore our Angular courses

Get started today and join over 50,000 developers.