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

Viewed 20249

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!

8 Answers

No.

<template>
  <div></div>
  <div>~someone~</div>
</template>

Yes.

<template>
  <div>
    <div></div>
    ~someone~
  </div>
</template>

If you do not use a "div" tag just inside the "Template" tag, you will get the same error. (By the way, it was possible to use other than div tags)

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 a 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.

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.

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>

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

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

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