ui
ux
vue
nuxt
last updated: October 13, 2021

Enjoyable micro-interactions with animated icons

How I use Lottie in Vue.js to render animated icons

Introduction

Animated icons are a great way to make micro-interactions on your application just a little more enjoyable and understandable. I use them in my applications a lot. Not long ago they've always seem kind of difficult to get but I'm going to show you that it shouldn't be hard. We're going to create a Lottie icon component in Vue that will render animated icons like this (gif looping the animated icon).

Lottie allows designers to create and ship beautiful animations without an engineer having to recreate it. Or for a developer it can be as easy as downloading a json file and loading it in your app.

You can find the end result of what we're going to build on Github. Let's dive in.

Setup

Installing Nuxt

We're going to use Nuxt to quickly create a Vue app whilst simplifying the process npx create-nuxt-app. Select the options to your liking. I especially recommend Tailwindcss for easy styling. You'll see me using their classes w-32 for example.

Installing Lottie

Next we install lottie-web npm i lottie-web. Lottie is a library that parses Adobe After Effects animations exported as json with Bodymovin and renders them.

Getting the icons

For this tutorial we're going to use an icon library of Lordicon I really like and use myself. They offer a free tier with 50 animated icons you can customize on their site. Of course there are a lot more alternatives like this list of free icons.

Creating the Lottie component

Let's get to work. Inside your components folder create a folder named icon and inside this folder a file named Lottie.vue. Add the following inside the template of the component.

components/icon/Lottie.vue
<template>
  <div
    ref="lavContainer"
    :style="{
        overflow: 'hidden',
    }"
  />
</template>

This div will display the icon. We add the ref attribute of 'lavContainer' so we can reference this DOM element. Add the following script to the component.

components/icon/Lottie.vue
<script>
  import lottie from 'lottie-web'

  export default {
    props: {
      // This will be the icon json file
      json: {
        type: Object,
        required: true,
      },
    },

    mounted() {
      // When the component is mounted, lottie will do it's work creating a svg and renders the icon.
      this.anim = lottie.loadAnimation({
        container: this.$refs.lavContainer,
        renderer: 'svg',
        animationData: this.json,
      })
    },
  }
</script>

We defined a prop json which we'll later use to set the animationData for Lottie. We also we referenced the container where we want to render and defined that we want to render the icon as an svg and. Now we have a Lottie component we can use to create our first icon.

This was the hardest part. Now you'll see how simple it is to create an icon.

Creating the heart icon

For readability I like to create a different icon component for each different icon. Let's create a heart icon. We create the file components/icon/Heart.vue.

components/icon/Heart.vue
<template>
  <icon-lottie :json="json" />
</template>

<script>
  import IconLottie from './Lottie'
  import json from '~/assets/heart.json'

  export default {
    components: {
      IconLottie,
    },

    data() {
      return {
        json,
      }
    },
  }
</script>

That's it. We created a component with the sole purpose of importing the json from our assets.

Showing the icon

Let's use this component on our main page. In pages/index.vue add the component.

pages/index.vue
<template>
  <div>
    <icon-heart class="w-64 h-64" />
  </div>
</template>

<script>
  import IconHeart from '~/components/icon/Heart.vue'

  export default {
    components: {
      IconHeart,
    },
  }
</script>

There you go. You'll see a looping icon on your main page. We're almost there.

Making the icon interactive

Of course we want the option whether the icon should loop and what about only playing when we hover the icon. We only have to add a few things.

components/icon/Lottie.vue
<template>
  <div
    ref="lavContainer"
    :style="{
      overflow: 'hidden',
    }"
    @mouseenter="playAnimation"
    @focus="playAnimation"
    @blur="stopAnimation"
    @mouseleave="stopAnimation"
  />
</template>

<script>
import lottie from 'lottie-web'

export default {
  props: {
    // This will be the icon json file
    json: {
      type: Object,
      required: true,
    },
    loop: {
      type: Boolean,
      default: false,
    },
  },

  mounted() {
    // When the component is mounted, lottie will do it's work creating a svg and renders the icon.
    this.anim = lottie.loadAnimation({
      container: this.$refs.lavContainer,
      renderer: 'svg',
      animationData: this.json,
      autoplay: false, // Prevents playing on load
      loop: this.loop, // Option whether you want to keep playing
    })
  },

  methods: {
    playAnimation() {
      this.anim.play() // Starts animation
    },
    stopAnimation() {
      this.anim.stop() // Stops animation
    },
  },
}
</script>

As you can see we in the template we added mouse and focus events. This will trigger the methods that will play and stop the animation. We also added a prop for looping, which is false by default. Lastly we set the autoplay option in the loadAnimation function to false and loop to the prop value. And there you go. This is all you need to have an icon for micro-interactions.

Conclusion

We've seen that adding a animated icon to your Vue project isn't so hard. If you want another icon, you can simply create a new component and load another json object. There's no need to recreate what your designer has already done or do you need a developer when you just finished designing your icons.

I now hope you can bring some extra flair to your applications. Please let me know what you think of this approach and share with me what icons you're using.