vue.js wrong transition group animation position

There is a bug in transition-group!

When you bind the key of li as the index, every time you remove a li, the animation always happend at the last li element.

So, if you want to use the animation with li , you can bind the key with number in your case.

<transition-group name="mix"
                  mode="out-in">
    <li class="alert alert-success list-unstyled"
        style="height: 40px; padding: 10px 15px;margin-bottom: 8px;cursor: pointer;"
        v-for="(number,index) in myNumbers"
        @click="removeNumber(index)"
        :key="index">
        {{number}}
    </li>
</transition-group>

vs

<transition-group name="mix"
                  mode="out-in">
    <li class="alert alert-success list-unstyled"
        style="height: 40px; padding: 10px 15px;margin-bottom: 8px;cursor: pointer;"
        v-for="(number,index) in myNumbers"
        @click="removeNumber(index)"
        :key="number">
        {{number}}
    </li>
</transition-group>

Finally, if you use animation with transition-group , do not bind the key to index , instead of item or number (in your case).

No matter what , make sure the key has the unique value.


Solution

Don't use index anywhere in the v-bind:key when using transition or transition-group.

Explanation

There is a bug/missing documentation, as well as bad documentation in the cookbook on vuejs.org, but there's a detailed explanation in the comments [1] on how indexes work, but no recognition this is a problem for developers in it's current state.

I have posted a few times to github, but the Vue.js developers there seem dismissive at best and refuse to either document this behavior or recognize this as a problem.

Reproduction of bug/error

There are three examples in the codepen below. The #1 works, the #2 uses :key="index" (your specific error above) and #3 uses :key="item +'_'+ index".

#2 and #3 give the error you are experiencing.

https://codepen.io/megacromulent/pen/wEzWNL

Summary of codepen:

This one works: (using item as :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="item">
    {{item}}
  </li>
</transition-group>

This one fails: (using index as :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="index" >
    {{item}}
  </li>
</transition-group>

This one fails worse: (concatenating index with string in :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="item + '_' + index" >
    {{item}}
  </li>
</transition-group>

Bug report (rejected)

I submitted this bug report to Vue.js devs here:

"Transition-group animates only last element if using index as the key"

https://github.com/vuejs/vue/issues/8718

It got closed instantly, so based on their input (requested I do a PR for comment, but that is not in my wheelhouse) I followed up with this feature request for the dev build to give an error, which would solve the problem at it's root.

Feature request (follow up, also rejected)

"Dev build console error when using index in :key value with v-for and transitions"

https://github.com/vuejs/vue/issues/8730

It seems reasonable to put a dev error on this issue, but the vue.js developers seem to think we should be able to figure this out on our own. I hope they come around and see this as a real issue. It's cost me hours of testing and reporting time to figure out.

I hope this helps other devs wasting time with this issue.

References

[1] https://github.com/vuejs/vue/issues/8718#issuecomment-416909724