Getting Started with Component Transitions in Vue

When we build applications, we aim to make them easy on the eye. We want our users to have a smooth experience using it, and to feel our application flowing from one point to another, rather than just jump between screens.

If we switch components without transitions, we see a sharp change every time a new component is called up. This is not ideal and can result in our users having a poor experience with our application.

In this tutorial, we will look at how to improve the flow of our application using component transitions in Vue.

Prerequisites

  1. Vue CLI 3 for installing Vue
  2. Knowledge of JavaScript
  3. Knowledge of Vue.js

Setup Our Application

To begin, we will create a Vue application. Run the following command:

$ vue create component-transitions
$ cd component-transitions

Once we are done creating the application, we need to define a component we will use for the transitions.

Update The App Component When we create a new Vue application, the CLI creates an App.vue file inside the ./src directory. Open the file and update the style section as follows:

[...]
<style>
    [...] 
    h3 {
        margin: 40px 0 0;
    }
    ul {
        list-style-type: none;
        padding: 0;
    }
    li {
        display: inline-block;
        margin: 0 10px;
    }
    a {
        color: #42b983;
    }
</style>

We created global styles we wish to share across all our components. This way, we will not have to add styles per component again.

Update The HelloWorld Component Our Vue application also comes with a HelloWorld.vue file in located in ./src/components directory. Open the file and edit as follows:

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'HelloWorld',
        props: {
            msg: String
        }
    }
</script>

Create The About Component We are going to create a new component About.vue inside the ./src/components directory. Open the file and add the following:

<template>
    <div>
        <h1>{{ msg }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'About',
        props: {
            msg: String
        }
    }
</script>

Create Another Component We are going to create another component Extra.vue inside the ./src/components directory. Open the file and add the following:

<template>
    <div>
        <h1>{{ intro }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'Extra',
        props: {
            msg: String
        },
        data(){
            return {
                intro : "Extra"
            }
        },
        watch: {
            msg : {
                immediate: true, 
                handler(val, oldval) {
                    //
                }
            }
        }
    }
</script>

For our extra component, we have added a watch method to track the updates to the msg prop. When the message prop updates, we want to update the intro property.

We defined it this way to allow us to use transitions on the component.

Rendering Our Components

Vue provides a variety of ways to apply transition effects when items in a component are updated or when components themselves are changed. It ranges from applying CSS classes for transitions and animations to using 3rd party JavaScript libraries for transition effects.

The first set of transitions we will define will be on change of components. We will use conditional rendering to display the components we created and apply transition as they render.

Import The Components We need to import the components we created into our App.vue component. Open the file and edit as follows:

[...]
<script>
    import HelloWorld from './components/HelloWorld.vue'
    import About from './components/About.vue'
    import Extra from './components/Extra.vue'

    export default {
        name: 'app',
        components: {
            HelloWorld, About, Extra
        }
    }
</script>

Use The Components Now that we have imported the components, let us use it in our App component. Edit the App.vue file as follows:

<template>
    <div id="app">
        <img src="./assets/logo.png">
        <HelloWorld msg="Welcome to your Vue.js application"/>
        <Extra :msg="extra"/>
        <About msg="This is the About page"/>
        <button @click="changeExtra">Update Extra</button>
    </div>
</template>

We defined a function changeExtra to listen for button clicks and also bound the msg prop for the Extra component to extra attribute. Now, let’s create the extra attribute and changeExtra method. We will just leave the Vue.js logo there so the page doesn’t feel empty ?

Edit the file as follows:

[...]
export default {
    name: 'app',
    components: {
        HelloWorld, About, Extra
    },
    data(){
        return {
            extra : "Extra"
        }
    },
    methods : {
        changeExtra(){
            this.extra = "This is extra"
        }
    },
}
[...]

Define Links For Switching Components We are going to show one component at a time. To do this, we will have a simple set of links that would allow us to state which component to use at a certain time.

Open the App.vue file and add the following:

<template>
    <div id="app">
        [...]
        <div>
            <ul>
                <li @click="showHome">Home</li>
                <li @click="showAbout">About</li>
                <li @click="showExtra">Extra</li>
            </ul>
        </div>
    </div>
</template>

Then add the methods we used above:

[...]
methods : {
    [...]
    showHome(){
        this.displayHome = true
        this.displayAbout = false
        this.displayExtra = false
    },
    showAbout(){
        this.displayHome = false
        this.displayAbout = true
        this.displayExtra = false
    },
    showExtra(){
        this.displayHome = false
        this.displayAbout = false
        this.displayExtra = true
    }
},
[...]

Finally, we define the properties — displayHome, displayAbout, displayExtra.

[...]
data(){
    return {
        extra : "Extra",
        displayHome : true,
        displayAbout : false,
        displayExtra : false
    }
},
[...]

We set displayHome to true so that anytime we load our application, it shows up first. The rest is false so they do not show up.

Conditional Rendering Of Our Components Now that we have defined links for showing our components, let’s render them based on certain conditions. Still in the App.vue file, edit it as follows:

<template>
    <div id="app">
        <img src="./assets/logo.png">
        <HelloWorld msg="Welcome to your Vue.js application" v-if="displayHome"/>
        <About msg="This is the About page" v-if="displayAbout"/>
        <div v-if="displayExtra">
            <Extra :msg="extra"/>
            <button @click="changeExtra">Update Extra</button>
        </div>
        [...]
    </div>
</template>

So, we have completely rendered all of our components, now we can add transitions to it. Hurray!!!

Defining Transitions On Data Change

We will modify Extra component. We want to add a simple transition effect when we update the data inside of it. Open the Extra.vue file in the ./src/components/ directory and edit as follows:

<template>
    <div>
        <transition name="fade">
            <h1 v-if="!msg">{{ intro }}</h1>
        </transition>
        <transition name="fade">
            <h1 v-if="msg">{{ msg }}</h1>
        </transition>
    </div>
</template>
[...]
<style scoped>
   .fade-enter-active{
        transition: opacity 1.5s;
    }
    .fade-leave-active {
        opacity: 0;
    }
    .fade-enter, .fade-leave-to {
        opacity: 0;
    }
</style>

This is a simple component. When we click the Update Extra button, we will notice a slide fading transition occur. The transition is very noticeable, so our users must see it.

We are able to achieve the transition by wrapping our element in a Vue transition element and then defining the effect we want the transition element to use. In our case, we used opacity to make the component appear and disappear.

For data change transitions, you might want to use state transition as it provides a more robust experience. Read more about State Transitions.

Vue provides hooks at different stages of the transition cycle that we can hook into and define how we want the transition to be. I’ve added an image below from Vue.js website to illustrate this:

Vue Transition Diagram

v represents the name of our transition. In the case of the Extra component, we replace v with fade to have fade-enter in place of v-enter and so on.

Defining Transitions On Component Change

Define Transition On The HelloWorld Component Now, to the App component where we will explore different other ways to implement transitions. Let’s define the transition on the HelloWorld component. Open the App.vue file and edit as follows:

<transition name="welcome">
    <HelloWorld msg="Welcome to your Vue.js application" v-if="displayHome"/>
</transition>

Our transition will be named “welcome”. Now, add the transition classes to get your desired effect:

<style scoped>
    /* Welcome Styles */
    .welcome-enter {
        transform: translateX(10px);
        opacity: 0;
    }
    .welcome-enter-active {
        transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
    }
    .welcome-leave-active, .welcome-leave-to {
        opacity: 0;
    }
</style>

Now, every time we click the Home link, there will be a little shaking ? as our component it shows.

PS: We created a new style element and added ‘scoped` to it.

Define Transition On The About Component We will take a similar step with what we did for the HelloWorld component. Open the file and add the following:

[...]
<transition name="about">
    <About msg="This is the About page" v-if="displayAbout"/>
</transition>
[...]

Then add the transition effect:

<style scoped>
    [...]
    /* About Styles */
    .about-enter {
        width: 30%;
        opacity: 0;
    }
    .about-enter-active {
        transition: all 2s ease-in-out;
    }
    .about-leave-active, .about-leave-to {
        opacity: 0;
    }
    .about-enter-to {
        width:100%;
        opacity: 1;
        margin-left: auto;
    }
</style>

Define The Transition On Extra Component Finally, let’s also add a transition for enter and exit of the extra component:

[...]
<transition name="extra">
    <div v-if="displayExtra">
        <Extra :msg="extra"/>
        <button @click="changeExtra">Update Extra</button>
    </div>
</transition>
[...]

Then add the styles for the transition:

<style scoped>
    [...]
    /* Extra Styes */
    .extra-enter {
        transform: translateX(-200px);
        opacity: 0;
    }
    .extra-enter-to {
        transform: translateX(0px);
    }
    .extra-enter-active {
        transition: all 1s cubic-bezier(1.0, 0.5, 0.8, 1.0);
    }
    .extra-leave-active, .extra-leave-to {
        opacity: 0;
    }
</style>

And that’s it for component transitions.

Run The Application

Now that we are done defining transitions for our various components, let’s run the application and see what it looks like.

From your terminal, run the following command:

$ npm run serve

Then visit the application on the url that appears.

See A Demo

Conclusion

We have looked at vue component transitions in this tutorial. We saw how easy it is to add transitions to our application. I have to admit we kind of overdid the transition thing and used effects we may not want to use in a real application. The entire goal was to show that anything is possible.

Try to use different CSS transitions for your components and see what you can come up with.