brand logo

ドキュメント

<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>
サンプルコードの編集とプレビューexamples > advanced > teleport

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設計が可能になります。ぜひ実務での導入を検討してみてください。