DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for How to make an animated dropdown with Vue and Tailwindcss
Fayaz Ahmed
Fayaz Ahmed

Posted on

How to make an animated dropdown with Vue and Tailwindcss

There will be a time when you have to make a custom dropdown, I happened to make one recently at work and this is the approach I took.

I will be creating a Nuxt.js project since that's what I am usually preferring over vanilla Vue these days.

Alright, let’s do this.

TL;DR Here's the demo


1. Setting up our project.

To create a Nuxt project run npx create-nuxt-app dropdown and select Tailwindcss as our choice of framework when setting up the project.

Creating a new project

Nuxt is still in the process of adding the newly released Tailwindcss 2.0, hence we will be installing the v2 manually, in order to that. Let's run a few commands in our project

npm i -D tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
Enter fullscreen mode Exit fullscreen mode

This will update the Post css in our nuxt project which is necessary to run the latest version of Tailwind.

Since I won't be changing any of tailwind's config, so I won't create a custom config file, if you want to know how to how to customise tailwindcss.

2. How does it work?

So, a dropdown will basically have three things technically.

  1. A button or link which is the users action.
  2. A card element which will be displayed when the above button/link is clicked or hovered.
  3. A hidden wrapping div which will be acting as a container for the button and the dropdown content

How the dropdown works

3. Making the dropdown

I will be making a vue component, which is better for isolating the dropdown's state, making sure the code is readable and clean.

PS, you can clear out the boilerplate from index.vue in pages & default.vue in layouts folders resp.

  1. Import a component called <dropdown> in your index.vue page.
<template>
  <div class="min-h-screen flex items-center justify-center">
    <dropdown />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode
  1. Create a file called dropdown.vue in the components folder.

Now let's add some code, a lot of code actually, but that is what we need when we need a good looking UI tbh, there's not short cuts.

<template>
  <div
    class="relative inline-block text-left text-gray-800"
    v-on-clickaway="closeMenu"
  >
    <div>
      <span class="rounded-md shadow-sm">
        <button
          @click="isMenuOpen = !isMenuOpen"
          type="button"
          class="inline-flex items-center justify-between w-full rounded-md border border-gray-300 h-10 px-4 py-4 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-100 active:text-gray-800 transition ease-in-out duration-150 btn-focus"
          id="options-menu"
          aria-haspopup="true"
          aria-expanded="true"
        >
          <span> {{ label }} </span>
          <img
            src="https://s.svgbox.net/hero-solid.svg?ic=chevron-down&fill=grey-800"
            class="-mr-1 ml-2 h-5 w-5"
          />
        </button>
      </span>
    </div>
    <transition
      enter-active-class="transition ease-out duration-100"
      enter-class="transform opacity-0 scale-95"
      enter-to-class="transform opacity-100 scale-100"
      leave-active-class="transition ease-in duration-75"
      leave-class="transform opacity-100 scale-100"
      leave-to-class="transform opacity-0 scale-95"
    >
      <div
        v-if="isMenuOpen"
        class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg text-sm overflow-hidden border z-20"
      >
        <div
          class="rounded-md bg-white shadow-xs"
          role="menu"
          aria-orientation="vertical"
          aria-labelledby="options-menu"
        >
          <div>
            <div class="bg-gray-100 p-4 flex items-center">
              <div class="w-full">
                <img
                  class="h-8 w-8 rounded-full mb-2"
                  src="https://fayazz.co/fayaz.jpg"
                  alt="avatar"
                />
                <p class="font-semibold text-base">Fayaz Ahmed</p>
                <button
                  class="flex items-center justify-between w-full focus:outline-none"
                >
                  <p class="text-gray-600">fayaz@email.com</p>
                  <img
                    src="https://s.svgbox.net/hero-solid.svg?ic=cog&fill=grey-700"
                    class="h-4 w-4"
                  />
                </button>
              </div>
            </div>
          </div>
          <div class="border-t border-gray-100"></div>
          <div class="py-1">
            <nuxt-link to="/" class="p-4 flex items-center space-x-2">
              <img
                src="https://s.svgbox.net/hero-outline.svg?ic=currency-rupee"
                class="h-6 w-6"
              />
              <span> Transaction History </span>
            </nuxt-link>
            <nuxt-link to="/" class="p-4 flex items-center space-x-2">
              <img
                src="https://s.svgbox.net/hero-outline.svg?ic=heart"
                class="h-6 w-6"
              />
              <span> Favourites </span>
            </nuxt-link>
          </div>
          <div class="border-t border-gray-100"></div>
          <div class="py-1">
            <nuxt-link
              to="/"
              @click.native="isMenuOpen = false"
              class="p-4 flex items-center space-x-2"
            >
              <img
                src="https://s.svgbox.net/hero-outline.svg?ic=logout"
                class="h-6 w-6"
              />
              <span> Logout </span>
            </nuxt-link>
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

PS, I have also installed a clickaway plugin for my project called vue-clickaway. You can just import it as a directive in your component to handle the clicks outside the dropdown and close it.

Here's what I did to animate the dropdown

I used the vue transition component to make it work and these are the tailwind classes, which did the magic.

enter-active-class="transition ease-out duration-100"
enter-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
Enter fullscreen mode Exit fullscreen mode

Basically, it's just scaling the dropdown card to 95 and back to 100.

Let me know if you need any help on this.

Top comments (5)

Collapse
anthonygushu profile image
Anthony Gushu

This is a great tutorial and I love the effort you put into the graphics, also the effort of presenting this in multiple formats.

Quick suggestion, those code blocks would look real nice with some syntax highlighting on em!

Collapse
fayaz profile image
Fayaz Ahmed Author

That is exactly what I thought and I am planning on building something for this.

Better code embeds

Collapse
pratik149 profile image
Pratik Rane

This is neat! I also needed something like "vue-clickaway". Thank you for mentioning it.

I was curious to know what went into the script tag, and how did you configure "vue-clickaway" in Nuxtjs. It would have been better if you also had mentioned the code.</p> <p>A github repo or codesandbox would also have been appreciated. Nonetheless, this also helped me. Thanks!</p>

Collapse
luciantartea profile image
Lucian Tartea

Great tutorial Fayaz, nice work

Collapse
mananchawla2005 profile image
Manan Chawla

Oh nice i love tailwindcss

🌚 Life is too short to browse without dark mode