Vue Transitions and Animations
Tags: vue, javascript, learning, webdev
Published: 2020-05-07 15:26:50

---
title: Vue Transitions and Animations
published: true
description: Transitions and animations help bring web apps to life. In this tutorial, we explore these concepts from within Vue and how you can implement them.
tags: vue, javascript, learning, webdev
canonical_url: https://blog.jscrambler.com/vue-transitions-and-animations/
cover_image: https://blog.jscrambler.com/content/images/2020/05/jscrambler-blog-vue-transitions-animations.jpg
---

Like many JavaScript front-end frameworks, having the ability to display transition effects for various UI actions is a core feature of Vue.

With Vue, it’s easy to create animations for actions like adding and removing items to lists, or toggling an element on and off.

In this article, we'll look at some basic animation features that are built into Vue.js.

## Basic Animation
We can create basic transitions by defining the CSS class that Vue looks for to create the transition effect and apply the style we want to it.

For transitions, the following classes will be used by Vue to style the transition effect:

* `v-enter`: Start state to enter. This class is applied before the element is inserted and removed one frame after the element is applied.

* `v-enter-active`: The class that's applied before the element is inserted into the DOM. This class is removed when the transition or animation finishes. It can also be used to define the duration, delay and easing curve for the entering transition. The easing is the rate of change of the element being animated.

* `v-enter-to`: The class for the ending state for entering. It's added one frame after the element is inserted, which is the same time that the `v-enter` class is removed.

* `v-leave`: This class is applied when the element starts leaving the DOM and when the leaving transition is triggered. The class is removed after one frame.

* `v-leave-active`: This represents the active state for the leaving transition. It's applied during the whole leaving phase. It's added immediately when the leave transition is triggered and removed when the transition finishes. Use this class to define the duration, delay, and easing for the leaving transition.

* `v-leave-to`: The ending state for the leave transition. This class is applied one frame after the leaving transition is triggered, which is the same time that the `v-leave` class is removed. This class is removed from the element being animated when the transition or animation is done.

`v-` is the prefix that can be replaced by the name of our animation, which we set as the value of the `name` prop of the `transition` component, which we'll use to add animation to our app.

For instance, we can create a simple transition effect that's displayed when we toggle an element on and off by writing the following code:

`index.js`

```js
new Vue({
  el: "#app",
  data: {
    show: true
  }
});
```

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity 0.3s;
      }
      .fade-enter,
      .fade-leave-to {
        opacity: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <button @click="show = !show">
        Toggle
      </button>
      <transition name="fade">
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

The animation code is all in `index.html`. We added the Vue `transition` component that's built into the library.

In the same file, we have the CSS that's defined as follows:

```css
.fade-enter-active,
.fade-leave-active {
    transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
    opacity: 0;
}
```

In the code above, we have the `fade-` prefix in each of our classes, which corresponds with the value of the `name` prop that's set in the `transition` component.

In each class, we just defined the styling that Vue looks for as we outlined above.

Then, when we click the Toggle button, we see that the word 'foo' will have a fading effect as it's being toggled on and off.

We can change the timing of the transition by adding easing as follows:

`index.html`

```html
...
    <style>
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity 1s cubic-bezier(1, 0.2, 0.8, 1);
      }
      ...
    </style>
...
```

In the code above, we have `cubic-bezier(1, 0.2, 0.8, 1)` which sets the rate of change of the opacity from coordinate from (1, 0.2) and (0.8, 1) by the [cubic bezier](https://cubic-bezier.com/) curve directory.

The curve looks like the curve that's outlined in the [Mozilla docs](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function) — we just have different coordinates.

We have eased in our code so that we can have a variable rate of change of the opacity. This results in transition effects that are more interesting than simple linear transitions.

## Scaling Effects

In addition to fading effects, we can change our transition to resize our element instead of having a fading effect.

To make an effect that skew the p element, we can create an animation with the following example:

`index.js`

```js
new Vue({
  el: "#app",
  data: {
    show: true,
    timer: undefined
  },
  beforeMount() {
    this.timer = setInterval(() => {
      this.show = !this.show;
    }, 1000);
  },
  beforeDestroy() {
    clearInterval(this.timer);
  }
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      p {
        font-size: 30px;
      }
      .scale-enter-active {
        animation: bounce-in 1s reverse;
      }
      .scale-leave-active {
        animation: bounce-in 1s;
      }
      @keyframes bounce-in {
        0% {
          transform: skewY(0deg);
        }
        25% {
          transform: skewY(2deg);
        }
        50% {
          transform: skewY(-5deg);
        }
        75% {
          transform: skewY(0deg);
        }
        100% {
          transform: skewY(-120deg);
        }
      }
    </style>
  </head>
  <body>
    <div id="app">
      <button @click="show = !show">
        Toggle
      </button>
      <transition name="scale">
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

`index.js` is the same as the previous example.

In the code above, we have the `bounce-in` animation that transforms the `p` element by changing its angle with `skewY`

We apply the transition every second with the `setInterval` callback that toggles the `this.show` value between `true` and `false` after 1 second.

## Custom Transition Classes

We can set our own transition class by passing in a few props to the `transition` component. They're the following:

* `enter-class`
* `enter-active-class`
* `enter-to-class` (available since 2.1.8+)
* `leave-class`
* `leave-active-class`
* `leave-to-class` (available since 2.1.8+)

They correspond to the transition stages that are outlined above.

We can use them as follows:

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .enter,
      .leave {
        animation: bounce-in 0.5s;
      }
      .active,
      .leave-active {
        animation: bounce-in 0.5s reverse;
      }
      @keyframes bounce-in {
        0% {
          transform: skewY(0deg);
        }
        50% {
          transform: skewY(70deg);
        }
        100% {
          transform: skewY(150deg);
        }
      }
    </style>
  </head>
  <body>
    <div id="app">
      <transition
        enter-class="enter"
        enter-active-class="active"
        leave-class="leave"
        leave-active-class="leave-active"
      >
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

`index.js` is the same as the previous example.

In the code above, we specified our own class names for the transition stages.

We specified the class names as the value of the props, and then we used them in the `style` tag by specifying them with the `animation`.

## Transition Durations

We can specify the `duration` prop to specify the duration of the transition effect.

For instance, we can use that as follows:

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .fade-enter-active,
      .fade-leave-active {
        transition: all 2s;
        transition-timing: ease-in-out;
      }
      .fade-enter,
      .fade-leave-to {
        opacity: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <transition name="fade" :duration="2000">
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

`index.js` is the same as the previous example.

In the code above, we have `:duration="2000"` to make the transition duration 2s.

We can also specify the duration for the enter and leave phases separately by passing in an object as follows:


```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity 1s cubic-bezier(1, 0.2, 0.8, 1);
      }
      .fade-enter,
      .fade-leave-to {
        opacity: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <button @click="show = !show">
        Toggle
      </button>
      <transition name="fade" :duration="{ enter: 800, leave: 500 }">
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

We have `:duration="{ enter: 800, leave: 500 }"` to specify the duration for the enter phase as 0.8s and the leave phase as 0.5s respectively.

## JavaScript Animations and Transition Hooks

We can attach event listeners to watch events that are emitted by various phases of the transition.

In each hook, we can get the element being animated with the `el` parameter of each hook.

The `enter` and `leave` hooks also have the `done` function that can be called to end the animation. The `done` function is needed to be called by JavaScript animations and is optional with CSS animations. Otherwise, the animation will be run synchronously.

These hooks are used for creating JavaScript animations mainly. We don't need them for CSS hooks.

We can create animations for Vue apps with the [Velocity](https://github.com/julianshapiro/velocity) library.

`index.js`

```js
new Vue({
  el: "#app",
  data: {
    show: true
  },
  methods: {
    beforeEnter(el) {
      el.style.opacity = 0;
      el.style.transformOrigin = "left";
    },

    enter(el, done) {
      Velocity(el, { opacity: 1, fontSize: "2.5em" }, { duration: 1300 });
      Velocity(el, { fontSize: "1em" }, { complete: done });
    },
    leave(el, done) {
      Velocity(
        el,
        { translateX: "25px", rotateZ: "270deg" },
        { duration: 1200 }
      );
      Velocity(el, { rotateZ: "220deg" }, { loop: 2 });
      Velocity(
        el,
        {
          rotateZ: "75deg",
          translateY: "50px",
          translateX: "30px",
          opacity: 0
        },
        { complete: done }
      );
    }
  }
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="show = !show">
        Toggle
      </button>
      <transition
        @before-enter="beforeEnter"
        @enter="enter"
        @leave="leave"
        :css="false"
      >
        <p v-if="show">foo</p>
      </transition>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we have the Velocity library so that we can create JavaScript animations with the DOM object that's in the parameter.

We styled the `p` element in the `beforeEnter` hook to style it when the transition starts.

We set the `p` element's opacity to 0 and the base placement of the element with the `transformOrigin` property to 0.

In the `enter` hook, we set the opacity and the font size when the `p` element is being inserted into the DOM. We also add our styling to the `p` element when it's removed from the DOM.

We added some rotation effects and some font size changes to make our `p` element look more interesting when clicking on Toggle to remove the `p` element when it's present in the DOM.

The `done` function that's in the parameter for `enter` and `leave` methods is used as a callback for when the animation is complete.

## List Transitions

To add transitions for `v-if`, we can also add transitions for when an item that's being rendered by `v-for` is being added and removed from the DOM.

Instead of the `transition` component, we use the `transition-group` component to apply the transition effect.

For instance, we can create a transition effect to show an animation when items are being added and removed from a list as follows:

`index.js`

```js
new Vue({
  el: "#app",
  data: {
    items: [1, 2, 3, 4, 5]
  },
  methods: {
    randomIndex() {
      return Math.floor(Math.random() * this.items.length);
    },
    add() {
      this.items = [...this.items, ++this.items[this.items.length - 1]];
    },
    remove() {
      this.items.splice(this.items.length - 1, 1);
    }
  }
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .list-enter-active,
      .list-leave-active {
        transition: all 1s;
      }
      .list-enter,
      .list-leave-to {
        opacity: 0;
        transform: translateY(40px);
      }
    </style>
  </head>
  <body>
    <div id="app">
      <button @click="add">Add</button>
      <button @click="remove">Remove</button>
      <transition-group name="list" tag="p">
        <span v-for="item in items" :key="item">
          {{ item }}
        </span>
      </transition-group>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we defined the styling for the transition phases as follows:


```css
.list-enter-active,
.list-leave-active {
    transition: all 1s;
}
.list-enter,
.list-leave-to {
    opacity: 0;
    transform: translateY(40px);
}
```

The transition phases are the same as the `v-if` transitions. We can apply styles when an element is being added and removed.

Once again, the name of the `name` prop matches the `name-` prefix of the CSS code.

The `tag` prop lets us specify the tag of the wrapper element. In our example, we make the wrapper element the `p` element.

## State Transitions

We can also animate component state changes. To make this easy, we use the [GreenSock](https://greensock.com/) library.

For instance, we can create an element that animates the number that we entered into the input as we change it, as follows:

`index.js`

```js
new Vue({
  el: "#app",
  data: {
    number: 0,
    tweenedNumber: 0
  },
  computed: {
    animatedNumber() {
      return this.tweenedNumber.toFixed(0);
    }
  },
  watch: {
    number(newValue) {
      gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
    }
  }
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model.number="number" type="number" step="20" />
      <p>{{ animatedNumber }}</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we have the `number` watcher that calls:

```js
gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
```

to animate the number as it's being changed.

## Conclusion

Creating transitions is easy with Vue. We can easily create them with the `transition` component for `v-if` transitions.

To animate `v-for` transitions, we can use the `transition-group` component.

We can create CSS transitions by prefix-specific classes with the value that we pass in as the value of the `name` prop.

Also, we can create JavaScript animations with the listeners that we can add to our components and we can use the Velocity library to add JavaScript animations.

---

Now that you have covered Vue animations, check out our other in-depth [Vue tutorials](https://blog.jscrambler.com/tag/vue-js?utm_source=dev.to&utm_medium=referral&utm_campaign=vue-transitions) — including our tutorial about <a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=vue-transitions">protecting your source code</a>.