# The difference between transition and transition-group components in Vue

Animations seem to be a necessity these days in frontend development, improving the user experience in apps by a significant margin. Thankfully vue.js shipped two built-in components that abstract away the complexities of animating our apps; `transition` and `transition-group`.

In this article, we'll be looking at a brief overview of the similarities and differences between these two components, how to use them and possible gotchas when working with them.

First off, we look at the similarities:

## Similarities

These two components as I mentioned earlier are used for animating between elements and components in our vue.js app.

* Both components are wrapped around the elements or components to be animated.
* Both components require a `name` attribute indicating the name of the animation to be applied.

Here's a high-level refresher on how to use these components:

```html
<transition name="fade">
  <!-- elements to be animated -->
</transition>

<transition-group name="fade">
  <!-- elements to be animated -->
</transition-group>
```

That's just about how similar these components are, now its time to look at their differences.

## Differences

The major difference between the `transition` and `transition-group` component is how they are used.

### How to use the `transition` component

The `transition` component is used to animate elements or components that fall under these categories:

1. Dynamic components
2. Conditionally displayed components (`v-show`)
3. Conditionally rendered components (`v-if`)
4. Root nodes of components
5. `router-view` components

#### Example with dynamic components

Below is an example of how you would use the `transition` component with dynamic components.

```html
<template>
	<div>
    	<transition name='fade'>
    		<component :is="currentComponent"></component>
        </transition>
    </div>
</template>

<script>
import UserOne from '~/components/users/One.vue'
import UserTwo from '~/components/users/Two.vue'
export default{
	props: {
    	userId: {
        	type: Number,
            required: true
        }
    }
	components:{
    	UserOne,
        UserTwo
    },
    computed:{
    	currentComponent(){
        	return this.userId === 1? 'UserOne' : 'UserTwo'
        }
    }
}
</script>
```

In the snippet above, two components will be toggled based on the value of the `userId` prop, we use the `transition` component to animate the process.

#### Example with conditionally displayed components

```html
<template>
	<div>
    	<button @click="showDescription = !showDecription">toggle description</button>
    	<transition name='bounce-up'>
    		<p v-show="showDescription">
            	This is a decription.
            </p>
        </transition>
    </div>
</template>

<script>
export default{
	data(){
    	return {
        	showDescription: false
        }
   	}
}
</script>
```

The example above uses the conditional display directive (`v-show`) to toggle the display of the element and we can now animate when the element appears and disappears.

#### Example with `router-view` component

If our app had one base component that was responsible for rendering all route components, usually (`App.vue`), we could wrap the `router-view` component with a `transition` component to animate when routes are being moved to and from.

```html
<template>
	<div>
    	<nav>
        	<router-link to="/">Home</router-link>
            <router-link to="/about">About</router-link>
            <router-link to="/contact">Contact us</router-link>
        </nav>
        
       	<transition :name="transitionName">
        	<router-view></router-view>
		</transiton>
    </div>
</template>

<script>
export default {
    data(){
		return {
        	transitionName: 'fade-up'
		}
    }
	watch: {
    	'$route'(to, from){
            const toDepth = to.path.split('/').length
            const fromDepth = from.path.split('/').length
            this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
        }
    }
}
</script>
```

### How to use the `transition-group` component

The `transition-group` component has a different use-case when dealing with animations.

`transition-group` is used when dealing with the entry and exit of **multiple** components or elements in the DOM (eg. rendering lists).

Before we get into get code examples, let's look at how `transition-group` differs from `transition`

* An element is actually wrapped around all elements being rendered, by default its `span` but it can be changed with the `tag` attribute.
* Elements inside the `transition-group` component must have a `key` attribute with unique values (using the indices of the element does not work, it is not unique).
* The CSS animations are applied to the individual elements and not the wrapper element.

```html
<template>
<div>
  <h2>Todos:</h2>
  <transition-group name="fade-x" tag="ol">
    <li v-for="todo in notDone" :key="todo.id">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
      </label>
    </li>
    </transition-group>
</div>
</template>

<script>
export default {
  data(){
    return{
      todos: [
        { id: 1, text: "Learn JavaScript", done: false },
        { id: 2, text: "Learn Vue", done: false },
        { id: 3, text: "Play around in JSFiddle", done: true },
        { id: 4, text: "Build something awesome", done: false }
      ]
    }
  },
  methods: {
  	toggle: function(todo){
    	todo.done = !todo.done
    }
  }, 
  computed: {
  	notDone(){
    	return this.todos.filter(todo=> !todo.done)
    }
  }
}
</script>

<style>
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}

.fade-x-enter-active, .fade-x-leave-active{
   transition: all .3s;
}

.fade-x-enter, .fade-x-leave-to{
  opacity: 0;
  transform: translateX(20px)
}
</style>
```

Now if a task is checked off, you can notice the animation before the element leaves the DOM.

You can create a new [fiddle](https://jsfiddle.net) here and paste the snippet above to test it out.

## TLDR

If you didn't have time to stick around long enough to read the entire article, here's a summary:

* Use `transition` when only one element or component will be rendered at a time, and `transiton-group` for multiple.
* `transition-group` elements must have unique key attributes.
* Use the `tag` attribute on the `transition-group` component to change the kind of element that wraps all elements within.
