written by Andre Liem
24/01/2018

Build a Vue.js Drop Down Profile Menu component

Welcome to the second post in the weekly to bi-weekly series on creating basic components for your Vue.js project. In this tutorial, I will build a basic drop down menu for editing a profile. Using functional CSS, this time with TachyonCss and some Vue.js transitions, you can build the basis for a simple dropdown in no time! (Code available at the bottom of this post)

Introduction

In this tutorial, I'll walk you through the steps in building a basic drop down menu for a typical profile menu. Although it's often tempting to reach for the bootstrap framework when building something like this, I prefer starting with functional inline CSS to prototype the component. This way you can really tweak it to meet your needs and then wrap it up into reusable CSS if needed. This is especially important when you want to build custom functionality like transitions, which often need to get right in between HTML tags to work well.

Disclaimer: The code has not gone through any extreme browser testing. You might have to modify the CSS to make it backwards compatible with legacy browsers.

Start at the End

Like the previous post, I prefer building components by starting with the finished UI or static HTML + CSS. Then I work from there towards the internals of what makes it work. Here is a picture of what the final product will look like.

Goal

So here I want to build a button which includes the user's name, mug and a basic drop down icon which will be provided by font awesome.

The majority of the UI was easy to build by refering to the Tachyon CSS Component Documentation.

The Template

Lets start by looking at the Vue.js template stripped of most of the CSS and HTML details.

<script id="dropdown" type="x/template">
  <div>
    <a href="#" v-on:click.prevent="showDropDown=!showDropDown">
      <div>Catness</div>
      <img src="..." alt="avatar">
      <i :class="{ 'fa-caret-up': showDropDown, 'fa-caret-down': !showDropDown }" class="fa" aria-hidden="true"></i>
    </a>
    <div v-if="showDropDown">
      <ul class="menu list pl0 pa0 ma0">
        <li v-for="link in links" class="list">
          <a href="#" class="dd-link pointer hover-bg-moon-gray">{{link.name}}</a>
        </li>
      </ul>
    </div>
  </div>
</script>

It's pretty easy, all we need is the button link that brings the drop down into view. We have showDropDown and links as the only data attributes needed to make this work. When showDropDown is true, we show the dropdown and hide when it's false, this is not rocket science!

The component code is below:

<script type="text/babel">
const DropDown = Vue.component("dropdown", {
  template: "#dropdown",
  data() {
    return {
      showDropDown: true,
      links: [
        {
          name: "Account"
        },
        {
          name: "Profile"
        },
        {
          name: "Logout"
        }
      ]
    };
  }
});

let App = new Vue({
  el: "#app",
  components: {
    DropDown
  }
});
</script>

When the user clicks the button we trigger v-on:click.prevent="showDropDown=!showDropDown" which just toggles the value.

A note about the CSS

It's worth reviewing the CSS for this as it's using Tachyon CSS which is a functional framework which encourages composition of predefined CSS rules. This is not the same as writting css inline with style!

For this project I've used LESS and defined the styling rules for the menu and links to keep the HTML a bit cleaner. Pure functional CSS followers might not like this approach and would prefer keeping it inline. I personally like a mixed approached, where classes responsible for margin, padding, and general layout rules go inline and then the reusable CSS into a file.

I firmly believe that if you get into the practice of using functional CSS for building a new UI component, you'll be able to do it at least 2 times faster than if you built it with a traditional semantic approach. In the end my result does create some semantic CSS, but the difference is that I'm doing this after I've prototyped the component inline. I didn't apply this to everything, so what you see on the Code Sample will be a bit of a mix of both Functional and Utility.

<style type="text/less">
@import (less) "//cdnjs.cloudflare.com/ajax/libs/tachyons/4.9.1/tachyons.css";

.menu {
  .bg-near-white;
  .b--solid;
  .br--bottom;
  .bw1;
  .b--black-20;
  .white-80;
  .br2;
}

.menu li {
  .ba;
  .bl-0;
  .bt-0;
  .br-0;

  &:not(:last-child) {
    .b--solid;
    .b--black-30;
  }
}

.dd-link {
  .f6;
  .pa2;
  .link;
  .dim;
  .w-100;
  .h-100;
  .dib;
  .b--white-10;
  .black-80;
}
</style>

Animate It

Something I love about Vue.js is how easy it is to make things come to life with the transition features. Lets make this drop down a bit fancier by adding a transition for it to appear and disappear. Here is a gif of what it should look like:

Animated
And below is the relevant code we need to make this happen

<transition name="slide-fade">
  <div class="w4 mt1" v-if="showDropDown">
    <ul class="menu list pl0 pa0 ma0">
      <li v-for="link in links" class="list">
        <a href="#" class="dd-link pointer hover-bg-moon-gray">{{link.name}}</a>
      </li>
    </ul>
  </div>
</transition>
<style type="text/less">
.slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .2s ease;
}
.slide-fade-enter { 
  transform: translateY(-50px);
  opacity: 0;
}
.slide-fade-leave-to {
 transform: translateY(-50px);
  opacity: 0; 
}
</style>

It's that easy, all we need is a transition tag with a name that refers to the CSS class.

The CSS defines some specific transitions with the following post fix naming conventions -enter-active, -leave-active, -enter, and -leave-to. Vue.js transitions looks for these and then applies it accordingly.

In this sample, I've added a negative translation on the Y axis to make the menu appear like it's coming from the button.

It would be possible to make each menu item drop down in more of a staggered fashion using a transition-group, but I'll leave that challenge up to you or if people request a more advanced tutorial on Vue.js transitions I'll consider doing it.

Conclusion

There you have it, with a relatively small CodePen you have a reusable DropDown component that has a nifty transition. The Code Pen for this is available here and on Github here. I hope you found this post useful! Please subscribe to our newsletter if you haven't already and follow us on Twitter to stay on top of Vue.js!