Image

animating-vue

6 min read
Last update: December 19, 2021

Group Transitions

So far we’ve learned how to transition individual components/elements in and out of our interfaces, and applied that concept to transitioning between route-level page components with Vue Router. But what if we have a group of components/elements to which we want to apply the same transition?

For example, every time we add a new item to a list, we might want the item to transition into that group in a specific way. Or we may have a group of elements that we want to reorder in the same way as filters are updated. To achieve this kind of group-based transition behavior, we can harness the power of Vue’s built-in <transition-group> component, which functions similarly to the <transition> component, but is designed for use with a group of components/elements.

    Let’s start understanding how it works with a simple example.

    ---

    ## A Simple List Transition

    We know that displaying data in a list is very common, so let’s start there. After all, a list is simply a **group** of `<li>` elements. So let’s say we have a list of contacts, and as we add a new contact to the list, we want it to transition into the list (into the group) in a specific way.

        We can start with the code below and solve from there.

        📃 **src/views/List.vue**

        ```html
        <template>
            <div>

                <input v-model="newContact" placeholder="Name" type="text" />
                <button @click="addContact">Add Contact</button>

                <ul>
                    <li v-for="(contact, index) in contacts" :key="index">
                        {{ contact }}
                    </li>
                </ul>

            </div>
        </template>

        <script>
            export default {
                data() {
                    return {
                        newContact: "",
                        contacts: [
                            "Beau Thabeast",
                            "Cindy Rella",
                            "Alice Wunderlind"
                        ]
                    }
                },
                methods: {
                    addContact() {
                        this.contacts.push(this.newContact)
                        this.newContact = ""
                    }
                }
            }
        </script>
        ```

        As you can see, our starting code simply contains a `template` that displays the list of `contacts` from our data, which is an array we can add to. So if we want a transition to be applied every time a new list item is added to that group, we can simply switch out our `ul` for the `transition-group` component, like so:

        📃 **src/views/List.vue**

        ```html
        <transition-group tag="ul">
    <li v-for="contact in contacts" :key="contact">
        {{ contact }}
    </li>
```

Notice how we’ve add the tag attribute and set it to "ul". This is because the transition-group renders an element that wraps the group itself. While the default element that transition-group renders is a span, we can change it to something else like a div, or for our current use case: a ul. You can think of the tag as what you otherwise would’ve wrapped the group of child elements with, because that’s essentially what happens when the transition-group renders anyhow.

Note: The transition component does not render an element; this behavior is unique to transition-group

The transition-group won’t yet do anything because, just like the transition component, we’ll give it the name of the transition we want applied to every member of the group. We’ll create a similar transition from the previous lesson, and give this a name of "slide-up".

📃 src/views/List.vue

<transition-group name="slide-up" tag="ul">
    <li v-for="contact in contacts" :key="contact">
        {{ contact }}
    </li>
</transition-group>

Then over in our App.vue file’s style section, we’ll build out the slide-up transition.

📃 src/App.vue

.slide-up-enter {
transform: translateY(10px); /* start 10px down*/
opacity: 0;
}

.slide-up-enter-active {
transition: all 0.2s ease;
}

In this simple example, we are only transitioning elements into the list and not out of it, so we can remove the leave-based transition classes.

Now, as we add new members to the contacts list, we’ll see them slide-up into it.

If you’re wondering why we used 10px to start from lower down on the page instead of -10px, that’s a great question! Remember, a webpage’s coordinates start at (0,0) from the upper lefthand corner of the page. So going down the page is actually going “up” in the Y coordinate direction.


Triggering Transitions on Initial Render

If we refresh the page, we’ll notice that our list looks like it’s slide-fading into place.That’s only because the entire route-level component is transitioning in like that (remember: we added slide-fade as our page transition). However, if we specifically wanted to make it so that the list would slide-up when the page (and therefor the list) was initially rendered, we can achieve that quite easily by using the appear attribute, like so:

📃 src/views/List.vue

<transition-group name="slide-up" tag="ul" appear>
    <li v-for="contact in contacts" :key="contact">
        {{ contact }}
    </li>
</transition-group>

The appear attribute is our way of telling the transition-group that not only do we want the slide-up transition to happen every time a new member of the group is added, but also when the entire group (the entire ul) is first rendered.

Now, when we refresh the page and our component initially loads, we’ll see those list items slide-up into place.

Note: The appear attribute can also be used on the transition component. It is not exclusive to transition-group.


Moving Items within a Group

If we were to add a feature to sort this list in some way, such as an alphabetical sorting method, what would happen when the items in our list moved into their new position?

For example, if our code had a sort button:

📃 src/views/List.vue

<template>
    ...
    <button @click="sortContacts">Sort</button>
    ...
</template>

And a new alphabetical sorting method:

📃 src/views/List.vue

methods: {
...
sortContacts() {
this.contacts = this.contacts.sort()
}
}

When we click the sort button, we’ll see our list items just kind of snap into their new position. That’s not bad, but wouldn’t it be nice if we could fine-tune how the items in our list move as they’re sorted? We can make use of the v-move transition class to adjust how our elements are moving as they change position within the group.

Let’s add v-move to our slide-up transition styles. Notice how the v- prefix is replaced by the name of our transition.

📃 src/App.vue

.slide-up-enter {
transform: translateX(10px);
opacity: 0;
}

.slide-up-enter-active {
transition: all 0.2s ease;
}

.slide-up-move {
transition: transform 0.5s ease-out;
}

If we check this out in the browser, now the members of our group are moving according to these styles. If we wanted to speed up or slow down the duration, or change the easing function, we could tweak this move style to our heart’s content.

If you’re curious how v-move works under the hood, it’s making use of the FLIP transition, which you learn more about here.


Let’s ReVue

That brings us to the end of our exploration of the fundamentals of group transitions. This topic is quite broad, as there are many ways that data (and the elements/components that display that data) can be grouped, and just as many ways to apply transitions to those groups. But with the fundamentals in place, I hope you feel confident to start writing your own when your app calls for them.

In the next lesson, we’ll dive into animating with JavaScript.