Dropdowns in Vue: The Right Way
Tags: vue, javascript, ux, design
Published: 2019-10-02 14:02:13

In this tutorial, we’ll go through an example of how you can implement a dropdown component using Vue. Like this:

{% codesandbox dropdown-2fzh6 %}

---

The most common way of making a dropdown in Vue has always been this way:

1. First, you define a toggler (usually a `<button>` or an `<a>`) with a click event that will call a toggle method.
2. You define the menu with a `v-if` directive that is bound to an active state.
3. You define a method toggle that will be triggered when clicking on the toggler and change the active state to true and consequently show the menu.

{% gist https://gist.github.com/victorronnow/8746511019429ce49fed2edd74fc3490 %}
Now, this way of doing is totally working and there is nothing wrong doing it. The problem is that you would need to define an active state on every component that has a dropdown. This kind of defeat the purpose of vue and the reusability of components.

---
I will show you my way of making dropdowns in a clean and reusable way.
I’m going to assume that you already have a vue project set up. If not, I recommend creating one using the  [vue-cli](https://cli.vuejs.org/).

We’ll start by scaffolding out the structure of our dropdown component:
{% gist https://gist.github.com/victorronnow/69aaae088b103185b59edc45f7ab8874 %}
We will then create 3 components:
* The `AppDropdown` component, which will act as the wrapper component. It will contain both the toggler and the menu.
* The `AppDropdownContent` component, which will act as the toggable menu.
* The `AppDropdownItem` component, which will be the actionable item inside the menu.

Let’s open the `AppDropdown.vue` file and write some code.

In here we’ll define a `<div>` that will contain the whole dropdown. We’ll add a slot with the name “`toggler`” and a button inside of it which will act as the default button toggle if none is provided.
{% gist https://gist.github.com/victorronnow/f4229589cfb51839a1e5255961a8a890 %}
Now, let’s open the `AppDropdownContent.vue` file.

We’ll add a `<div>` which will wrap the menu and use the `v-if` directive to only display it when it is active. 
{% gist https://gist.github.com/victorronnow/0a7b7bce6bbc2841ea3fc08d4fc4dd9a %}

You might ask yourself: where is the `active` state coming from?

Here comes the fun part: We need the `AppDropdownContent` component to receive that value in some way. The most logical way would be from the main `AppDropdown` component itself. But how in the hell could we do this?

For that, we’ll use the amazing *`provide`* and *`inject`* features provided by Vue. In our case the `AppDropdown` will “provide” the `active` state and the `AppDropdownContent` will “inject” it in itself.

Let’s go back to our `AppDropdown.vue` file.

We’ll add a sharedState object to the data with the property `active` in it, that will be set as `false` by default. We’ll define a `toggle()` method, that will switch the `active` state. After that, we’ll add a `@click` event to the main div that will call the `toggle()` method. Finally, we’ll `provide ()` the sharedState to every component inside the main `AppDropdown` component.
{% gist https://gist.github.com/victorronnow/c4c7450fb9c4b714a94341b26a1cdce5 %}
In the `AppDropdownContent` component, we now have the possibility to  `inject` the `sharedState` provided by the `AppDropdown`. Let’s create a computed property `active` and set it’s value to the one `sharedState` provides.
{% gist https://gist.github.com/victorronnow/d9a9c626bbabb2f14cadd2042da60b98 %}
And voilà!  You now how a fully working dropdown component that is fully customizable.

But wouldn’t be nice if you didn’t need to close it by clicking on the toggle again and just click outside of it?

Fortunately, there is this great plugin called `vue-clickaway` that allows us to do just this. Let’s install it: `npm i vue-clickaway`

NB: You might want to recompile your project after the install.

We’ll add the directive provided by `vue-clickaway` the `AppDropdown`. We’ll define an `away()`method and call it when click away is triggered.
{% gist https://gist.github.com/victorronnow/99378d55fa8b5e5e341771554447a68b %}
And that’s it! Now, you can simply add some styles to the dropdown and make it look shiny.

If you have any questions, don’t hesitate to reach out to me on twitter  [@victorronnow](https://twitter.com/victorronnow)