---
title: "Vue 3のTransitionの使い方｜TransitionGroup・mode・動かない原因を3.5.45で検証"
url: "https://www.issoh.co.jp/tech/details/9874/"
published: 2025-11-18
updated: 2026-11-08
categories: ["Vue.js"]
publisher: "株式会社一創"
---

# Vue 3のTransitionの使い方｜TransitionGroup・mode・動かない原因を3.5.45で検証

Vue 3の `<Transition>` は、要素がDOMに入るときと出るときにCSSクラスを順番に付け外しする組み込みコンポーネントです。動き自体はCSSの `transition` や `animation` が担い、Vueは「いつどのクラスを付けるか」を管理します。リストの追加・削除・並べ替えには `<TransitionGroup>` を使います。

この記事は2026年11月8日時点の安定版Vue 3.5.45を前提にしています。挙動はVue 3.5.45の開発用ビルドとヘッドレスのChrome 156で実行して確かめ、コード例は `@vue/compiler-sfc` でコンパイルが通ることを確認しました。

## まとめ：Vue 3のTransitionの要点

- 反応するのは `v-if`・`v-show`・`<component :is>`・`key` の変更の4つ。中に置ける要素は1つだけ。
- クラスは `v-enter-from`・`v-enter-active`・`v-enter-to` とleave側の3つで計6つ。`name="fade"` で接頭辞が `fade-` に変わる。
- `appear` の初回表示に付くのはenterのクラス。`v-appear-from` は `appear-from-class` で指定したときだけ使われる。
- 入れ替えは `mode="out-in"` が基本。既定では新旧の要素が同時にDOMに並ぶ。
- リストは `<TransitionGroup>`。`key` に配列の番号を使わず、削除する要素には `position: absolute` と幅の指定を付け、親を `position: relative` にする。
- ページ遷移は `<router-view>` のスロットで包み、同じ部品を使い回すルートには `:key="route.path"` を付ける。`<KeepAlive>` は `<Transition>` の内側に置く。
- 3.5.43以前は、複数ルートの部品を `out-in` で切り替えると画面が空になる。3.5.45へ更新し、ページ部品のルート要素は1つにする。

以下、受け持つ範囲から順に説明します。

## Vue 3のTransitionが受け持つ範囲とCSSだけで済む動きの境界

### Transitionが反応する4つの切り替え

[Vue公式ガイドのトランジションの章](https://ja.vuejs.org/guide/built-ins/transition)が挙げる発火条件は、`v-if`、`v-show`、`<component>` による動的コンポーネントの切り替え、特殊属性 `key` の変更の4つです。組み込みコンポーネントなので、インポートや登録は要りません。

DOMに入りも出もしない要素の色やサイズの変化には反応しません。ホバーで色を変えるといった動きは、`:class` の付け替えか `:style` のバインドで書きます。

### CSSのtransition・animationとVueのTransitionの役割分担

「トランジション」は、ある状態から別の状態へ移るときの変化を指す言葉です。CSSの `transition` は2つの状態の間を補間し、`animation` は `@keyframes` で途中の状態まで定義します。

Vueの `<Transition>` はどちらとも競合しません。`v-if` で消す要素は、削除を待たせないとアニメーションの前にDOMから外れてしまいます。Vueはクラスを付けて動きを始めさせ、`transitionend` か `animationend` を待ってから要素を外します。

### Transitionを使わずCSSだけで書ける条件

`@starting-style` と `transition-behavior: allow-discrete` を使えば、Vue側の仕組み無しでも一部の動きを書けます。

```
<script setup>
import { ref } from 'vue'
const open = ref(false)
</script>

<template>
  <button @click="open = !open">切り替え</button>
  <p class="panel" v-show="open">パネル</p>
</template>

<style>
.panel {
  opacity: 1;
  transition: opacity 0.3s linear, display 0.3s allow-discrete;
}
@starting-style {
  .panel { opacity: 0; }
}
.panel[style*="display: none"] {
  opacity: 0;
}
</style>
```

Chrome 156での結果は次のとおりでした。

| 書き方            | 現れる動き | 消える動き       |
| -------------- | ----- | ----------- |
| `v-show`＋CSSのみ | 動く    | 動く          |
| `v-if`＋CSSのみ   | 動く    | 動かない（即時に削除） |
| `<Transition>` | 動く    | 動く          |

`v-if` の消える動きはCSSでは書けません。さらに [MDNの transition-behavior](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/transition-behavior) はBaseline未達で、[互換データ](https://raw.githubusercontent.com/mdn/browser-compat-data/main/css/properties/transition-behavior.json)ではFirefoxは `display` の遷移に未対応、Safariは18からの対応です。[@starting-style](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@starting-style) 自体は2024年8月から主要ブラウザで使えます。製品では、現れる動きだけならCSSのみで済ませ、消える動きが要る箇所は `<Transition>` を使うのが安全です。

## Vue 3のTransitionの基本の書き方

フェードイン・フェードアウトの最小構成です。`<script setup>` の書き方は[Composition APIの書き方とOptions APIとの違い](/tech/details/3589/)で説明しています。

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

const show = ref(true)
</script>

<template>
  <button @click="show = !show">切り替え</button>
  <Transition name="fade">
    <p v-if="show">こんにちは</p>
  </Transition>
</template>

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

時間とイージングは `-active` クラスに、開始と終了の値は `-enter-from` と `-leave-to` に書きます。動かすプロパティは `opacity` と `transform` に寄せてください。`height` や `margin` はフレームごとにレイアウト計算が走るため、公式ガイドも注意を促しています。

### v-ifとv-showの違いと選び方

終わった後のDOMが違います。`v-show` は消える動きの後も要素が残り、`style="display: none;"` が付くだけでした。`v-if` は要素ごと取り除きます。頻繁に開閉するドロップダウンには `v-show` が向いています。閉じたときに子コンポーネントの状態を破棄したいモーダルは、そのコンポーネントに `v-if` を付けます。親のrefやストアに保存した状態は残ります。`@leave-cancelled` が呼ばれるのは `v-show` のときだけです。

## 6つのトランジションクラスが付く順番

enterとleaveにそれぞれ3つ、計6つのクラスが付きます。

| クラス              | 付くとき           | 外れるとき     |
| ---------------- | -------------- | --------- |
| `v-enter-from`   | 挿入の直前          | 挿入の1フレーム後 |
| `v-enter-active` | 挿入の直前          | enter終了時  |
| `v-enter-to`     | 挿入の1フレーム後      | enter終了時  |
| `v-leave-from`   | leave開始直後      | 1フレーム後    |
| `v-leave-active` | leave開始直後      | leave終了時  |
| `v-leave-to`     | leave開始の1フレーム後 | leave終了時  |

Chrome 156で記録した順番も、この表のとおりでした。公式ガイドには、CSS animationでは `*-enter-from` が `animationend` まで残るとあります。しかし3.5.45では、animationでもtransitionと同じく挿入の次のフレームで外れました。`@keyframes` を使う場合、`-enter-from` の値に頼らず `-enter-active` に動きを全部書くのが確実です。

### name属性で変わるクラスの接頭辞

`name` を付けないとクラスは `v-` で始まり、`name="fade"` なら `fade-enter-from` になります。`:name="transitionName"` のように動的にもでき、状態に応じてスライドの向きを変えられます。

### カスタムクラスでTailwind CSSやAnimate.cssと組み合わせる方法

`enter-active-class` などの6つのpropsで、クラス名そのものを差し替えられます。Tailwind CSS 4.3.5で確かめた書き方です。先の基本例のscriptと切り替えボタンを残し、Transition部分を次のコードに置き換えます。

```
<template>
  <Transition
    enter-active-class="transition-opacity duration-300 motion-reduce:transition-none motion-reduce:duration-0"
    enter-from-class="opacity-0"
    leave-active-class="transition-opacity duration-300 motion-reduce:transition-none motion-reduce:duration-0"
    leave-to-class="opacity-0"
  >
    <p v-if="show">Tailwindで動かす</p>
  </Transition>
</template>
```

動きを抑える設定では `motion-reduce:transition-none` だけでは足りません。`transition-property` が `none` になっても `duration-300` が残り、要素は動かないまま約0.3秒残りました。`motion-reduce:duration-0` を足すと、すぐに外れます。Animate.cssも `enter-active-class="animate__animated animate__tada"` のように渡せます。transitionとanimationを併用する場合は、どちらの終了を待つかを `type` で明示します。

## appearで初回表示を動かすときのクラス名

ページを開いた時点で表示されている要素は、既定では動きません。初回表示から動かすには `appear` を付けます。

```
<template>
  <!-- 初回表示は fade-enter-from / fade-enter-active が付く -->
  <Transition name="fade" appear>
    <p>初回から動く</p>
  </Transition>

  <!-- 初回表示だけ別の動きにしたいときはクラス名をpropsで指定する -->
  <Transition
    name="fade"
    appear
    appear-from-class="fade-appear-from"
    appear-active-class="fade-appear-active"
  >
    <p>初回だけ別の動き</p>
  </Transition>
</template>

<style>
.fade-enter-active {
  transition: opacity 0.3s ease;
}
.fade-enter-from {
  opacity: 0;
}
.fade-appear-active {
  transition: transform 0.6s ease, opacity 0.6s ease;
}
.fade-appear-from {
  opacity: 0;
  transform: translateY(20px);
}
</style>
```

`fade-appear-from` や `v-appear-from` というクラスは、Vue 3では自動では付きません。[Transition.ts](https://github.com/vuejs/core/blob/v3.5.45/packages/runtime-dom/src/components/Transition.ts)で `appearFromClass = enterFromClass` が既定値になっており、初回表示の要素に付いたのは `fade-enter-from fade-enter-active` でした。CSSに `.fade-appear-from` を書いたのに効かないときは、propsを渡していないことが原因です。

## modeによる要素の入れ替え順の制御

`v-if`／`v-else` や動的コンポーネントで要素を入れ替えるときは、`mode` で順番を決めます。

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

const saved = ref(true)
</script>

<template>
  <Transition name="fade" mode="out-in">
    <button v-if="saved" key="edit" @click="saved = false">編集</button>
    <button v-else key="save" @click="saved = true">保存</button>
  </Transition>
</template>
```

| mode     | 順番             | DOMに同時に並ぶ数 | 向く場面             |
| -------- | -------------- | ---------- | ---------------- |
| 指定なし     | leaveとenterが同時 | 2          | 重ねて表示するUI        |
| `out-in` | leave完了後にenter | 1          | ボタン・タブ・ページ       |
| `in-out` | enter完了後にleave | 2          | 新要素の表示まで旧要素を残すUI |

指定なしでは両方がレイアウトに参加するため、位置がずれます。入れ替えは `out-in` を既定にしてください。連続で40ミリ秒おきに5回切り替えても、`out-in` ではDOMに並ぶ要素は最大1つで、最後の値が残りました。

JavaScriptフックの順番には癖があります。`out-in` でも、新要素の `@before-enter` は旧要素の `@after-leave` より先に呼ばれました。旧要素の片付けを `@after-leave` に書き、新要素がその結果を読む設計は順番が逆になります。

中身だけ変わる要素は、`key` を変えて別要素として扱わせます。`<span :key="count">{{ count }}</span>` は値が変わるたびに `@enter` が呼ばれ、`key` が無いと1回も呼ばれませんでした。

## TransitionGroupによるリストの追加・削除・並べ替え

### TransitionGroupの基本構文と一意なkeyの指定

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

const items = ref([1, 2, 3])
let next = 4
const add = () => items.value.splice(Math.floor(Math.random() * items.value.length), 0, next++)
const remove = (i) => items.value.splice(i, 1)
</script>

<template>
  <button @click="add">追加</button>
  <TransitionGroup name="list" tag="ul" class="list">
    <li v-for="(item, i) in items" :key="item" @click="remove(i)">{{ item }}</li>
  </TransitionGroup>
</template>

<style>
.list {
  position: relative;
  padding: 0;
}
.list-move,
.list-enter-active,
.list-leave-active {
  transition: all 0.4s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
.list-leave-active {
  position: absolute;
  width: 100%;
}
</style>
```

[公式ガイド](https://ja.vuejs.org/guide/built-ins/transition-group)が挙げる `<Transition>` との違いは4つです。各要素に一意の `key` が必須、クラスは各要素に付く、`mode` は使えない、ラッパーは `tag` を指定したときだけ描画される。`tag` を省くと、`<ul>` の中に置いても余分な要素は増えません。HTMLに直接書くテンプレートでは `<transition-group>` とケバブケースで書きます。

### v-moveと削除時のposition: absoluteで崩れる幅

`.list-move` にtransitionを書くと、位置が変わった要素が滑らかに動きます。クラス名は `name` に `-move` を付けたもので、`move-class` で変えられます。

公式の例にある `.list-leave-active { position: absolute; }` の役割は、実測すると明確でした。これが無いと、消える要素が場所を占めたままなので、残りの要素は削除完了まで移動せず、実測では消えた瞬間に項目の高さに相当する20ピクセル分跳びました。`-move` クラスも付きません。

ただしこの1行だけでは別の崩れが起きます。幅300ピクセル・paddingとmarginが0の `<ul>` に数字1文字の項目を置き、ビューポート幅1280ピクセルで確かめた結果です。8pxは文字やフォント、1280pxはビューポート幅に依存します。

| CSS                        | 消える要素の幅         |
| -------------------------- | --------------- |
| `position: absolute` のみ    | 8px（中身の幅まで縮む）   |
| `width: 100%` を追加          | 1280px（画面幅に広がる） |
| さらに親へ `position: relative` | 300px（元のまま）     |

背景色や枠線のあるカードでは、この縮みがそのまま見えます。上のコード例のように、`absolute`・`width: 100%`・親の `position: relative` をセットで書いてください。親に `padding` があると絶対配置の幅はその分広がるので、例では0にしています。要素を少しずつ遅らせる演出は、`:data-index="index"` を持たせてJavaScriptフックで遅延を計算するのが公式の書き方です。

### TransitionGroupが動かない2つの原因

| 原因                   | 実測の結果             | 直し方                |
| -------------------- | ----------------- | ------------------ |
| `:key="index"`       | 先頭を消すと末尾が消える動きになる | データのIDをkeyにする      |
| 子が `display: inline` | moveクラスは付くが動かない   | `inline-block` にする |

どちらも警告は出ません。特に `:key="index"` は、`A・B・C` の先頭を消したときに `A` ではなく末尾の `C` の要素が消える動きをしました。番号が振り直されて、Vueが「末尾が消えた」と判断するためです。`<span>` のタグ一覧を並べ替えるときは `display` も確認してください。`transform` はインライン要素には効きません。

## Vue RouterとNuxtのページ遷移にTransitionを付ける手順

### router-viewのkeyとKeepAliveの入れ子順

Vue Routerでは `<router-view>` のスロットで受け取った部品を包みます。[公式のトランジションの章](https://router.vuejs.org/guide/advanced/transitions.html)と[スロットの章](https://router.vuejs.org/guide/advanced/router-view-slot.html)の形を合わせると次のようになります。

```
<template>
  <router-view v-slot="{ Component, route }">
    <Transition :name="route.meta.transition || 'fade'" mode="out-in">
      <KeepAlive>
        <component :is="Component" :key="route.path" />
      </KeepAlive>
    </Transition>
  </router-view>
</template>
```

Vue 3.5.45とVue Router 5.4.0で確かめると、落とし穴は2つありました。`/users/1` から `/users/2` のように同じ部品を使い回すルートは、`key` が無いと `@enter` が1回も呼ばれません。入れ子の順を `<KeepAlive>` が外側になるよう逆にすると、警告なしで状態が失われ、戻ったときにカウンターが0に戻りました。正しい順では値が残ります。

初回表示の扱いにも注意が必要です。公式によれば、ナビゲーションが非同期なので、`appear` を付けなくても最初のページで動きが走ります。止めたいときは `await router.isReady()` の後に `app.mount('#app')` を呼びます。

### Nuxt 4のpageTransitionとlayoutTransition

Nuxt 4.6.4では、ページ全体の遷移を設定ファイルで有効にします。[Nuxt 4の現行版と導入手順](/tech/details/9938/)も参照してください。

```
export default defineNuxtConfig({
  app: {
    pageTransition: { name: 'page', mode: 'out-in' },
    layoutTransition: { name: 'layout', mode: 'out-in' },
  },
})
```

CSSは `.page-enter-active` のように、`name` に合わせて書きます。ページごとに変えるなら `definePageMeta` の `pageTransition` です。[Nuxt公式](https://nuxt.com/docs/4.x/getting-started/transitions)は、レイアウトも変わる遷移ではページのトランジションは動かず、レイアウト側の設定が要ると書いています。ブラウザ標準のView Transitions APIは `experimental.viewTransition` で有効にできますが、名前のとおり実験的な機能です。

### out-inで画面が空になる条件と修正された版

ページ部品のルートが1要素でないと、`out-in` の切り替えで画面が空になることがありました。版ごとの実測結果です。

| 切り替える部品              | 3.5.43 | 3.5.44 | 3.5.45 | 3.6.0-rc.14 |
| -------------------- | ------ | ------ | ------ | ----------- |
| ルートが複数要素             | 空になる   | 正常     | 正常     | 正常          |
| コメント＋要素              | 空になる   | 正常     | 正常     | 正常          |
| テキストのみ               | 空＋エラー  | 空＋エラー  | 正常     | 空＋エラー       |
| `@leave` で即 `done()` | 空になる   | 空になる   | 正常     | 空になる        |

修正は[3.5.44と3.5.45の変更履歴](https://github.com/vuejs/core/blob/v3.5.45/CHANGELOG.md)に #15853 と #11824 として載っています。3.5.43以前を使っているなら更新してください。更新後も、複数ルートの部品は切り替えられるだけでアニメーションせず、開発時に `renders non-element root node` の警告が出ます。Nuxt公式もページのルートは1要素と定めています。部品を `<div>` で包むのが確実な対処です。

## JavaScriptフックによるGSAP連携と終了タイミングの制御

CSSで書きにくい動きは、フックで外部ライブラリに任せます。フックは `@before-enter`・`@enter`・`@after-enter`・`@enter-cancelled` と、leave側の同じ4つがenter／leave用です。初回表示には、これらとは別にappear系のフックもあります。

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

const show = ref(true)

function onBeforeEnter(el) {
  el.style.opacity = 0
}
function onEnter(el, done) {
  gsap.to(el, { opacity: 1, duration: 0.4, onComplete: done })
}
function onLeave(el, done) {
  gsap.to(el, { opacity: 0, duration: 0.4, onComplete: done })
}
</script>

<template>
  <button @click="show = !show">切り替え</button>
  <Transition
    :css="false"
    @before-enter="onBeforeEnter"
    @enter="onEnter"
    @enter-cancelled="el => gsap.killTweensOf(el)"
    @leave="onLeave"
  >
    <div v-if="show">GSAPで動かす</div>
  </Transition>
</template>
```

`:css="false"` を付けると、CSSトランジションの自動検出を省き、Vueによるトランジションクラスの付与も行わなくなります。このとき `@enter` と `@leave` では第2引数の `done` を必ず呼びます。`done` を受け取らない1引数の関数にすると、Vueはその場で終了とみなし、`@after-enter` が同じタイミングで呼ばれました。ライブラリ側の書き方は[Anime.js v4の変更点と使い方](/tech/details/12740/)でGSAPと比べています。

入れ子の要素を時間差で動かしても、自動の終了判定は直接の子要素だけを見ます。親が0.2秒、内側が0.25秒遅れの0.3秒のとき、内側の動きが終わる前に要素が外れました。内側の遅延を含む合計を `:duration="550"` や `:duration="{ enter: 500, leave: 800 }"` のようにミリ秒で渡します。

## Vue 3のTransitionが動かないときの確認点

原因はおおむね決まっています。上から順に確かめてください。

### nameとCSSクラスの不一致で要素が即座に消える症状

`name` とCSSのクラス名が食い違っていても、エラーは出ません。対応する `transition` が見つからない要素は、数フレームでDOMから外れます。動かないのに表示の切り替えだけは起きるときは、開発者ツールで `-enter-active` のクラス名を確かめます。

### Transitionの子要素数とコンポーネントの単一ルート制約

`<Transition>` の中に `<p>` を2つ並べると、「`<Transition> expects exactly one child element or component.`」というコンパイルエラーになります。開発用でも本番用でも同じです。複数並べたいならTransitionGroupを使います。

### ルートに置いたTransitionと外側のv-ifの関係

```
<!-- 動かない：Modalのルートに置いたTransitionは、外側のv-ifでは発火しない -->
<Modal v-if="open" />

<!-- 動く：開閉の状態をpropsで渡し、Transitionの子でv-ifを切り替える -->
<Modal :open="open" />
```

```
<script setup>
defineProps({ open: Boolean })
</script>

<template>
  <Transition name="fade">
    <div v-if="open" class="modal"><slot /></div>
  </Transition>
</template>
```

部品のルートを `<Transition>` にして親から `v-if` で消すと、Transitionごと消えるのでleaveは動きません。実測でも外側の `v-if` ではleaveフックが0回、propsで子の `v-if` を切り替えたときは1回でした。

### 再利用Transitionのscopedスタイルとスロットの関係

`<Transition>` を包んだ共通部品を作るとき、`<style scoped>` に書いたクラスはスロットで渡された要素に当たりません。公式ガイドもこの場面ではscopedを避けるよう注記しています。スタイルはグローバルに書き、衝突は `name` で防ぎます。

### prefers-reduced-motionで動きを止めるCSSとVueの待ち時間

OSの「視差効果を減らす」設定は、Vueでは自動では反映されません。3.5.45の `runtime-dom` にこの設定を扱う処理は無く、`reduce` を指定したChromeでも0.3秒の動きはそのまま再生されました。CSS側で止めます。

```
@media (prefers-reduced-motion: reduce) {
  .fade-enter-active,
  .fade-leave-active,
  .list-move,
  .list-enter-active,
  .list-leave-active {
    transition: none;
  }
}
```

`transition: none` なら、Vueは終了を待たずに要素を出し入れします。JavaScriptフックで動かしている場合は `window.matchMedia('(prefers-reduced-motion: reduce)').matches` で分岐し、動きを省くときも `done()` を呼んでください。呼ばないとleaveの要素がDOMに残り続けます。

## Vue 2からVue 3への移行で変わったトランジションの仕様

Vue 2は2023年12月31日でサポートが終了しています。[移行ガイド](https://v3-migration.vuejs.org/breaking-changes/transition.html)の変更点は次のとおりです。

| 項目                    | Vue 2                       | Vue 3                                 |
| --------------------- | --------------------------- | ------------------------------------- |
| enter開始クラス            | `v-enter`                   | `v-enter-from`                        |
| leave開始クラス            | `v-leave`                   | `v-leave-from`                        |
| クラス指定props            | `enter-class`・`leave-class` | `enter-from-class`・`leave-from-class` |
| transition-groupのラッパー | 既定で `<span>`                | 既定で無し                                 |
| ルートのtransition        | 外から切り替えで発火                  | 発火しない                                 |

CSSは `.v-enter` を `.v-enter-from` に、`.v-leave` を `.v-leave-from` に置換すれば移行できます。`<span>` ラッパーにスタイルを当てていたなら `tag="span"` を追加します。`-to` と `-active` のクラス名は変わっていません。

Vue 3.6は2026年10月30日公開の3.6.0-rc.14の段階で、まだ正式版ではありません。通常の仮想DOMの `<Transition>` はrc.14でも3.5と同じクラスと順番で動きました。Vapor Mode向けには [VaporTransition と VaporTransitionGroup](https://github.com/vuejs/core/blob/v3.6.0-rc.14/packages/runtime-vapor/src/index.ts) が用意されています。

## よくある質問

### Vueのトランジションとは何ですか？CSSのtransitionとの違いは？

Vueの `<Transition>` は、要素がDOMに入る・出るタイミングでクラスを付け外しする組み込みコンポーネントです。CSSの `transition` は値の変化を補間する仕組みで、動きそのものを担います。両者は競合せず、Vueは `transition` や `animation` の終了を待ってから要素をDOMから外します。この「消える前に待つ」部分が、CSSだけでは `v-if` に対して実現できません。

### v-appear-fromクラスはVue 3で使えますか？

自動では付きません。`appear` を付けた初回表示には `v-enter-from` などのenterクラスが使われます。初回表示専用のクラスを使いたいときは、`appear-from-class="v-appear-from"` のようにpropsで指定し、対応するCSSを別に書きます。propsを渡さずに `.v-appear-from` のCSSだけ書いても、そのクラスは要素に付かないので効きません。

### TransitionGroupでmodeは使えますか？

使えません。`mode` は1つの要素を入れ替える場面のための機能で、複数の要素を同時に扱うTransitionGroupには適用されないと公式ガイドに記載があります。リスト内の並べ替えや削除の動きは、`-move` クラスと `-leave-active` の `position: absolute` で作ります。旧要素が消えてから新要素を出したいなら、`<Transition>` の `out-in` を使います。

### TransitionGroupのtagは必須ですか？

必須ではありません。Vue 3では `tag` を省くとラッパー要素は描画されず、子要素だけが親の中に並びます。すでに `<ul>` を書いているなら省略できます。ただし `position: absolute` の基準が要るので、`tag="ul"` で付けた要素か外側の要素のどちらかに `position: relative` を指定してください。Vue 2の既定の `<span>` に頼っていたコードは `tag="span"` が要ります。

### Nuxtでも同じ書き方で使えますか？

使えます。`<Transition>` と `<TransitionGroup>` はVue本体の機能なので、Nuxtの部品の中でそのまま書けます。ページ全体の遷移だけは `nuxt.config` の `app.pageTransition` で指定する点が違い、部品のルート要素を1つにする必要があります。Nuxtの全体像は[Nuxtの解説](/tech/details/15790/)を参照してください。

## 関連記事

- [Composition APIとは？Options API・React Hooksとの違いとコンポーザブルの書き方【Vue 3.5】](/tech/details/3589/)
- [Nuxt 4とは？最新バージョンは4.6｜確認方法・Nuxt 3との違い・導入手順【2026年10月】](/tech/details/9938/)
- [Nuxtとは：Vue.jsとの違い・レンダリング方式・4系への移行手順と採用判断を実装視点で解説](/tech/details/15790/)
- [Anime.js v4の変更点と使い方｜v3からの移行手順とGSAPとの違い](/tech/details/12740/)
- [ReactとVue 3の違いを比較｜どっちを選ぶべきか【React 19.3・Vue 3.5対応】](/tech/details/2348/)

---

出典: [Vue 3のTransitionの使い方｜TransitionGroup・mode・動かない原因を3.5.45で検証](<https://www.issoh.co.jp/tech/details/9874/>)（株式会社一創）
