'Vue 3 – <Transition> renders non-element root node that cannot be animated

App.vue has a transition tag to fade the pages out and in.

<router-view v-slot="{ Component }">
   <transition name="fade" mode="out-in" appear>
      <component :is="Component"></component>
   </transition>
</router-view>

The Page.vue file has a simple structure, however it also has a basic sliderjs component which throws the error <Transition> renders non-element root node that cannot be animated. If the transition tag is removed, everything works fine.

<div v-if="page.isReady">
   <swiper>
      <swiper-slide>Slide 1</swiper-slide>
      <swiper-slide>Slide 2</swiper-slide>
      <swiper-slide>Slide 3</swiper-slide>
   </swiper>
</div>

https://swiperjs.com/vue/

The file also has the following:

import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/swiper.scss';

export default {
  components: {
    Swiper,
    SwiperSlide,
  },
  
  setup () {
    return {
      page: usePage()
    }
  }
}

Is there any trick to fix the error? Thanks for any tips!



Solution 1:[1]

Transitions require single children nodes. Therefore you can wrap the <component> tag inside a <div>, however, a plain <div> inside a <transition> won't trigger the transition, but changing the key attribute does.

We can obtain an unique key by getting the route name:

<router-view v-slot="{ Component, route }">
  <transition name="fade" mode="out-in">
    <div :key="route.name">  
      <component :is="Component"></component>
    </div>
  </transition>
</router-view>

This will effectively transition between routes with a different name, but if you also want to transition between routes of the same name with different parameters, you can use route.fullPath instead of route.name as the key.

Solution 2:[2]

I can't fully take credit for this one...but I was having a similar issue and the problem was I had multiple nodes in my view, and found this guy's post on the Vue.js forums:

Found my mistake too. Transition required a single root in components! Since Vue 3 no longer requires a single root node for components I thought this also applies to transitions. But it’s also logical. CSS requires a single root to which the transitions can refer.

Solution 3:[3]

I solved it, it was a minor mistake, there was a character outside a html tag, directly after the tag (comma).

<template>,
    <div>
      <div>
        <swiper>
          <swiper-slide>Slide 1</swiper-slide>
          <swiper-slide>Slide 2</swiper-slide>
          <swiper-slide>Slide 3</swiper-slide>
        </swiper>
      </div>
    </div>
</template>

Solution 4:[4]

your dynamic component instance must have a root element. in you example,'Swiper' and 'SwiperSlide' must have a root element!

Solution 5:[5]

don't use RouterView in component parameter of the router. if you need to do that put it inside a root element

Solution 6:[6]

When toggling between elements that have the same tag name, you must tell Vue that they are distinct elements by giving them unique key attributes. Otherwise, Vue’s compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, it’s considered good practice to always key multiple items within a component.

<div>
  <router-link to="/"></router-link>
  <router-link to="/about"></router-link>
</div>
<router-view v-slot="{ Component, route }">
  <transition name="route" :key="route" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

Solution 7:[7]

<router-view v-slot="{ Component }">
 <transition name="fade" mode="out-in" appear>
  <!-- root element -->
  <div>
    <component :is="Component"></component>
  </div>
 </transition>
</router-view>

Solution 8:[8]

Make sure you following Vue templates' single-root requirement

I got this warning when my Vue template had multiple root nodes, such as this:

<template>
  <input type="email" />
  <button>Validate</button>
</template>

Adding a wrapper element as a root fixed the issue, like so:

<template>
  <div>
      <input type="email" />
      <button>Validate</button>
  </div>
</template>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dexter Legaspi
Solution 3 To E
Solution 4 Charles Okwuagwu
Solution 5 Ali Chraghi
Solution 6 Joye
Solution 7 co yixia
Solution 8 AamirR