Fix: Invalid Transition Mode in Vue.js

Error message:
invalid <transition> mode: {mode}
Components 2025-01-25

What Causes This Warning?

This warning occurs when you provide an invalid value to the mode prop of Vue’s <Transition> component. Only in-out and out-in are valid mode values.

The Problem

<!-- ❌ Invalid mode values -->
<template>
  <Transition mode="fade">
    <Component />
  </Transition>

  <Transition mode="both">
    <Component />
  </Transition>

  <Transition mode="inout">
    <Component />
  </Transition>
</template>

The Fix

Use Valid Mode Values

<template>
  <!-- ✅ out-in: current element transitions out first, then new one in -->
  <Transition mode="out-in">
    <Component :key="componentKey" />
  </Transition>

  <!-- ✅ in-out: new element transitions in first, then current one out -->
  <Transition mode="in-out">
    <Component :key="componentKey" />
  </Transition>

  <!-- ✅ No mode: both transition simultaneously (default) -->
  <Transition>
    <Component :key="componentKey" />
  </Transition>
</template>

Mode Comparison

No Mode (Default)

Both elements transition at the same time:

<template>
  <Transition name="fade">
    <Component :key="current" />
  </Transition>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

out-in Mode (Most Common)

Old element leaves first, then new element enters:

<template>
  <!-- ✅ Best for most use cases -->
  <Transition name="fade" mode="out-in">
    <Component :key="current" />
  </Transition>
</template>

in-out Mode

New element enters first, then old element leaves:

<template>
  <!-- Useful for specific effects like overlapping cards -->
  <Transition name="slide" mode="in-out">
    <Component :key="current" />
  </Transition>
</template>

Common Scenarios

Tab Switching

<script setup>
import { ref } from 'vue'

const activeTab = ref('home')
</script>

<template>
  <div class="tabs">
    <button @click="activeTab = 'home'">Home</button>
    <button @click="activeTab = 'about'">About</button>
  </div>

  <!-- ✅ Use out-in for clean tab transitions -->
  <Transition name="fade" mode="out-in">
    <HomeTab v-if="activeTab === 'home'" key="home" />
    <AboutTab v-else key="about" />
  </Transition>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

Route Transitions

<template>
  <RouterView v-slot="{ Component, route }">
    <Transition name="page" mode="out-in">
      <component :is="Component" :key="route.path" />
    </Transition>
  </RouterView>
</template>

<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.3s ease;
}
.page-enter-from {
  opacity: 0;
  transform: translateX(20px);
}
.page-leave-to {
  opacity: 0;
  transform: translateX(-20px);
}
</style>

Dynamic Components

<script setup>
import { shallowRef } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

const current = shallowRef(ComponentA)

function toggle() {
  current.value = current.value === ComponentA ? ComponentB : ComponentA
}
</script>

<template>
  <button @click="toggle">Toggle</button>

  <Transition name="slide" mode="out-in">
    <component :is="current" />
  </Transition>
</template>

Slide Transition

<template>
  <Transition name="slide" mode="out-in">
    <div :key="step">
      Step {{ step }} content
    </div>
  </Transition>
</template>

<style>
.slide-enter-active,
.slide-leave-active {
  transition: all 0.3s ease;
}
.slide-enter-from {
  transform: translateX(100%);
  opacity: 0;
}
.slide-leave-to {
  transform: translateX(-100%);
  opacity: 0;
}
</style>

Why Modes Exist

Without modes, both elements exist in the DOM during the transition, which can cause:

  • Layout jumping (two elements taking space)
  • Overlapping content
  • Unpredictable visual results

Using mode="out-in" ensures only one element is visible at a time.

Quick Checklist

  • Use only out-in or in-out for the mode prop
  • out-in is usually what you want (old leaves, then new enters)
  • in-out is for special effects (new enters, then old leaves)
  • No mode = simultaneous transitions
  • Always use :key to trigger transitions between elements