<ClientOnly>
<ClientOnly> コンポーネントを使用して、クライアントサイドでのみコンポーネントをレンダリングします。
<ClientOnly> コンポーネントは、意図的にクライアントサイドでのみコンポーネントをレンダリングするために使用されます。
デフォルトスロットの内容はサーバービルドからツリーシェイクされます。(これは、その中で使用されるCSSが初期HTMLのレンダリング時にインライン化されない可能性があることを意味します。)
Props
placeholderTag|fallbackTag: サーバーサイドでレンダリングするタグを指定します。placeholder|fallback: サーバーサイドでレンダリングするコンテンツを指定します。
<template>
<div>
<Sidebar />
<!-- <Comment> コンポーネントはクライアントサイドでのみレンダリングされます -->
<ClientOnly fallback-tag="span" fallback="コメントを読み込んでいます...">
<Comment />
</ClientOnly>
</div>
</template>
Slots
#fallback: サーバーでレンダリングされ、<ClientOnly>がブラウザでマウントされるまで表示されるコンテンツを指定します。
<template>
<div>
<Sidebar />
<!-- これはサーバーサイドで "span" 要素をレンダリングします -->
<ClientOnly fallbackTag="span">
<!-- このコンポーネントはクライアントサイドでのみレンダリングされます -->
<Comments />
<template #fallback>
<!-- これはサーバーサイドでレンダリングされます -->
<p>コメントを読み込んでいます...</p>
</template>
</ClientOnly>
</div>
</template>
Examples
HTML要素へのアクセス
<ClientOnly> 内のコンポーネントは、マウントされた後にのみレンダリングされます。DOM内のレンダリングされた要素にアクセスするには、テンプレートリファレンスを監視できます。
<script setup lang="ts">
const nuxtWelcomeRef = useTemplateRef('nuxtWelcomeRef')
// コンポーネントが利用可能になったときにウォッチがトリガーされます
watch(nuxtWelcomeRef, () => {
console.log('<NuxtWelcome /> がマウントされました')
}, { once: true })
</script>
<template>
<ClientOnly>
<NuxtWelcome ref="nuxtWelcomeRef" />
</ClientOnly>
</template>
tips
このセクションは公式ドキュメントの翻訳ではなく、本サイト独自の補足記事です。
NuxtのClientOnlyコンポーネントとは?〜何が嬉しいのか〜
Nuxtはサーバーサイドレンダリング(SSR)を標準でサポートしており、初期表示の高速化やSEO対策に優れています。しかし、すべてのコンポーネントがSSRに適しているわけではありません。特にブラウザのAPIに依存するUIライブラリや、クライアントでのみ動作する処理を含むコンポーネントは、SSR時にエラーを起こしたり、期待通りに動作しなかったりします。
ここで役立つのが、ClientOnlyコンポーネントです。これは「この中のコンポーネントはサーバーではレンダリングせず、クライアントでのみ描画する」という宣言を可能にします。結果として、SSRの恩恵を受けつつ、クライアント限定の処理を安全に組み込めるようになります。
まず結論:ClientOnlyのポイント
- SSRでのエラー回避:ブラウザ依存の処理を含むコンポーネントをサーバーでレンダリングしないため、SSRエラーを防止できる
- Hydrationの不整合を防ぐ:サーバーとクライアントの描画差異によるHydrationエラーを回避
- フォールバック表示が可能:サーバー側で代替コンテンツ(プレースホルダー)を表示できる
- パフォーマンス制御:必要な部分だけクライアントレンダリングに限定し、初期表示を軽くできる
- 使いすぎに注意:多用するとSSRのメリットが薄れ、UXやSEOに悪影響を及ぼす可能性がある
いつ使うべきか?使わない方がよいケースは?
使うべきケース
- ブラウザAPIを使うUIコンポーネント
例:windowやdocumentを直接操作するカレンダーや地図コンポーネント - サードパーティのクライアント専用ライブラリ
SSR対応していないライブラリを使う場合 - 動的にクライアントでのみ生成されるコンテンツ
例:ユーザーのブラウザ情報に依存する表示や、クライアント側でのみ意味を持つUI
使わない方がよいケース
- SEOが重要なコンテンツ
ClientOnly内のコンテンツはサーバーでレンダリングされないため、検索エンジンに認識されにくい - 初期表示のパフォーマンスを重視する場合
ClientOnlyを多用すると、初期HTMLが軽くなる反面、クライアントでの再描画が増え、UXが悪化することも - 単純な静的コンテンツやSSR対応済みコンポーネント
これらは通常通りSSRでレンダリングしたほうがメリットが大きい
実務でよくあるユースケースとサンプルコード
1. ブラウザAPIを使うカレンダーコンポーネント
<template>
<div>
<h2>予約カレンダー</h2>
<ClientOnly fallback-tag="div" fallback="カレンダーを読み込み中...">
<CalendarComponent />
</ClientOnly>
</div>
</template>
この例では、CalendarComponentがwindowやdocumentを使うため、サーバーでのレンダリングを避けています。フォールバックとして「カレンダーを読み込み中...」を表示し、ユーザー体験を損なわない工夫もしています。
2. サードパーティのチャートライブラリを使う場合
<template>
<section>
<h3>売上チャート</h3>
<ClientOnly>
<SalesChart />
</ClientOnly>
</section>
</template>
多くのチャートライブラリはSSR非対応なので、ClientOnlyで囲むことで安全に利用可能です。
3. ユーザーのブラウザ情報に基づく表示切替
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const userAgent = ref('')
onMounted(() => {
userAgent.value = navigator.userAgent
})
</script>
<template>
<div>
<ClientOnly>
<p>あなたのブラウザは: {{ userAgent }}</p>
</ClientOnly>
</div>
</template>
navigator.userAgentはサーバーでは存在しないため、ClientOnlyで囲むことで安全に扱えます。
よくある落とし穴・注意点
SSRとHydrationの不整合
ClientOnlyはサーバーで何もレンダリングしないため、クライアントで初めて描画される際にDOMの差異が生じます。Nuxtはこれを吸収しますが、フォールバック表示がないと空白が目立つことがあります。必ずfallbackやfallbackTagで代替表示を用意しましょう。
CSSの扱い
ClientOnly内のコンポーネントで使われるCSSはサーバーでインライン化されないことがあります。結果として初期表示時にスタイルが適用されず、一瞬レイアウト崩れが起きることも。必要に応じてグローバルCSSや遅延読み込み対策を検討してください。
パフォーマンスへの影響
ClientOnlyを多用すると、SSRの恩恵が薄れ、初期HTMLが軽くなる反面、クライアントでの再描画負荷が増えます。特にモバイル端末ではUX低下の原因になるため、必要最小限に留めることが重要です。
SEOへの影響
ClientOnly内のコンテンツはサーバーに存在しないため、検索エンジンのクローラーに認識されません。SEOが重要なページでは使わないか、重要な情報は別途SSR対応させる工夫が必要です。
まとめ
NuxtのClientOnlyコンポーネントは、SSR環境でブラウザ依存の処理を安全に扱うための強力なツールです。使うことでSSRエラーやHydration不整合を防ぎつつ、クライアント限定のUIを実装できます。ただし、使いすぎるとパフォーマンスやSEOに悪影響が出るため、用途を見極めて適切に活用しましょう。
ClientOnlyは「クライアントでのみレンダリングしたい」コンポーネントを包むためのものです。SSR対応済みのコンポーネントには不要ですし、SEOが重要な部分には使わないのが基本です。
※このページは Nuxt.js 公式ドキュメントの翻訳ページです。
公式ドキュメントの該当ページはこちら:
https://nuxt.com/docs/3.x/api/components/client-only