Write JavaScript like a pro. Javascript Icon

Follow the ultimate JavaScript roadmap.

Build a Counter, Dropdown and Accordion in Vue Components!

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.

Angular Directives In-Depth eBook Cover

Free eBook

Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.

  • Green Tick Icon Observables and Async Pipe
  • Green Tick Icon Identity Checking and Performance
  • Green Tick Icon Web Components <ng-template> syntax
  • Green Tick Icon <ng-container> and Observable Composition
  • Green Tick Icon Advanced Rendering Patterns
  • Green Tick Icon Setters and Getters for Styles and Class Bindings

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:

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.

Learn JavaScript the right way.

The most complete guide to learning JavaScript ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover