<Teleport>
<Teleport> コンポーネントは、コンポーネントを DOM の異なる場所にテレポートします。
<Teleport> の to ターゲットは、CSS セレクタ文字列または実際の DOM ノードを期待します。Nuxt は現在、#teleports へのテレポートのみ SSR をサポートしており、他のターゲットへのクライアントサイドのサポートは <ClientOnly> ラッパーを使用します。
ボディテレポート
<template>
<button @click="open = true">
モーダルを開く
</button>
<Teleport to="#teleports">
<div v-if="open" class="modal">
<p>モーダルからこんにちは!</p>
<button @click="open = false">
閉じる
</button>
</div>
</Teleport>
</template>
クライアントサイドテレポート
<template>
<ClientOnly>
<Teleport to="#some-selector">
<!-- content -->
</Teleport>
</ClientOnly>
</template>
tips
このセクションは公式ドキュメントの翻訳ではなく、本サイト独自の補足記事です。
NuxtでのTeleport活用ガイド
VueのTeleportコンポーネントは、DOMツリーの異なる場所にコンテンツを「テレポート」できる強力な機能です。Nuxtではこの機能を活用することで、モーダルやツールチップ、ドロップダウンメニューなどのUIを柔軟に実装できます。
しかし、NuxtのSSR(サーバーサイドレンダリング)環境下ではTeleportの扱いに制約があり、適切に理解しないと意図しない動作やパフォーマンス問題を引き起こすことがあります。本記事では、Teleportの基本から実務での使いどころ、注意点までを丁寧に解説します。
まず結論:Teleportのポイントまとめ
- TeleportはDOMの任意の場所にコンテンツを移動できるVueの組み込み機能
- NuxtのSSRでは、
#teleportsという特定のターゲットのみが公式にサポートされている - クライアントサイド専用のターゲットにテレポートする場合は、
ClientOnlyでラップする必要がある - モーダルやツールチップなど、UIの重なりや構造上の制約を解決するのに有効
- SSRとCSRの差異によるHydrationエラーやパフォーマンス低下に注意が必要
いつ使うべきか・使わない方がよいケース
使うべきケース
-
モーダルやダイアログの実装
親コンポーネントのDOM階層に依存せず、画面の最上位に表示したい場合に最適です。 -
ツールチップやポップオーバー
親要素のCSS制約(overflow:hiddenなど)を回避し、画面上の任意の位置に表示したいとき。 -
グローバルなUI要素の管理
ナビゲーションメニューや通知バナーなど、アプリ全体で共通して使う要素を特定のDOMノードにまとめたい場合。
使わない方がよいケース
-
SSRでの動的なターゲット指定
NuxtのSSRは#teleports以外のターゲットを公式にサポートしていないため、動的にターゲットを切り替える用途には不向きです。 -
単純なDOM構造で問題がない場合
余計な複雑さを避けるため、特にテレポートが必要ないUIは通常のコンポーネント構造で十分です。
実務でよくあるユースケースとサンプルコード
1. モーダルウィンドウの実装
モーダルは画面の最上位に表示したいUIの代表例です。Teleportを使うことで、親コンポーネントのDOM階層に依存せずに表示できます。
<template>
<button @click="showModal = true">モーダルを開く</button>
<Teleport to="#teleports">
<div v-if="showModal" class="modal-overlay">
<div class="modal-content">
<p>これはモーダルの内容です。</p>
<button @click="showModal = false">閉じる</button>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>
<style>
.modal-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
display: flex; justify-content: center; align-items: center;
}
.modal-content {
background: white; padding: 1rem; border-radius: 4px;
}
</style>
2. ツールチップの表示
親要素のCSS制約を回避し、画面上の任意の場所にツールチップを表示したい場合に有効です。
<template>
<button @mouseenter="showTooltip = true" @mouseleave="showTooltip = false">
ホバーしてね
</button>
<Teleport to="#teleports">
<div v-if="showTooltip" class="tooltip">
ツールチップの内容
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const showTooltip = ref(false)
</script>
<style>
.tooltip {
position: fixed;
background: black; color: white; padding: 0.5rem;
border-radius: 3px;
top: 50px; left: 100px; /* 適宜調整 */
}
</style>
3. クライアントサイド専用のテレポート
SSRでサポートされていないターゲットにテレポートしたい場合は、ClientOnlyでラップしてクライアントレンダリング時のみ有効にします。
<template>
<ClientOnly>
<Teleport to="#some-other-target">
<div>クライアントサイドでのみ表示される内容</div>
</Teleport>
</ClientOnly>
</template>
よくある落とし穴・注意点
SSRとHydrationの不整合
NuxtのSSRでは、Teleportのターゲットは基本的に#teleportsに限定されています。これ以外のターゲットを使うと、サーバーとクライアントでDOM構造が異なり、Hydrationエラーが発生することがあります。
パフォーマンスへの影響
TeleportはDOMの移動を伴うため、頻繁に表示・非表示を切り替えるUIで乱用すると、再描画コストが増大しパフォーマンス低下を招くことがあります。必要な箇所に絞って使うことが重要です。
CSSの影響範囲
テレポート先のDOMは親コンポーネントのスコープ外になるため、CSSのスコープやスタイル継承に注意が必要です。グローバルスタイルやCSS変数を活用すると管理しやすくなります。
まとめ
NuxtでのTeleportは、UIの柔軟な配置を実現する強力なツールです。特にモーダルやツールチップのような画面上の重なりを制御したい場合に役立ちます。
ただし、SSR環境下での制約やHydrationエラー、パフォーマンス面の注意点を理解し、適切に使い分けることが重要です。クライアントサイド専用のターゲットにはClientOnlyを併用するなど、Nuxtの特性に合わせた実装を心がけましょう。
これらを踏まえれば、Teleportを活用した洗練されたUI設計が可能になります。ぜひ実務での導入を検討してみてください。
※このページは Nuxt.js 公式ドキュメントの翻訳ページです。
公式ドキュメントの該当ページはこちら:
https://nuxt.com/docs/3.x/api/components/teleports