slotを子コンポーネントへフォワーディングする

はじめに

今年ももう終わりですね〜、皆様はどんな一年だったでしょうか。 どうもfujimmm331です。

普段はRe:lationやRe:Chatの開発をしています。

以前、Vue の slot の基本的な使い方についてまとめました。

👉 https://blog.ingage.jp/entry/2025/09/05/095105

今回はその続編として、 親コンポーネントで定義された slot をラップした子コンポーネントへそのまま引き継ぐ(フォワーディングする) という少し応用的なパターンを整理します。

個人的に少しハマったポイントだったので、備忘録がてら残しておきます。

フォワーディングしたいケース

例えば次のようなケースです。

  • デザインや振る舞いを共通化した「ラッパーコンポーネント」を作りたい
  • ただし、中身の描画は呼び出し元で柔軟に制御したい
  • slot の書き味は、できるだけ元のコンポーネントと変えたくない

Re:lationではUiライブラリとしてVuetifyを採用しています。 Re:lation独自のスタイルを閉じ込めておき、一貫したデザインを提供するためにもベースコンポーネントを作成しております。

この時、例えばv-data-tableだと使用できるslotが27個近くあります。 そのうち、slotの名前が動的に決まるものも存在します。

https://vuetifyjs.com/ja/api/v-data-table/#slots

これだと個別にslotを定義することはなかなか難しいそうですね。

結論:slot をそのままフォワーディングする実装

まずは結論となるコードです。

<v-data-table
  class="base-v-table"
  :headers="headers"
  :items="items"
  :items-per-page="-1"
  fixed-header
  hide-default-footer
>
  // こちら
  <template v-for="(_, name) in $slots" :key="name" #[name]="slotData">
    <slot :name="name" v-bind="slotData" />
  </template>
</v-data-table>

$slots には、親コンポーネントで使用された slot の情報がオブジェクト形式で格納されています。 キー名にはslotの名前が使われているので、キー名から動的にslotを作成し、子コンポーネントへデータを流しています。

<template v-for="(_, name) in $slots" :key="name">

デメリット

フォワーディングする方法は便利ですが、$slots を動的に回す都合上、

  • どんな slot 名が来るのか
  • slotData の型が何か

がコード上で固定されません。 結果として、型の利点が弱まりやすいです。

まとめ

  • $slots は「親で使われた slot の一覧」
  • $slots を v-for で回し、<slot :name="name" /> を使えば slot をそのままフォワーディングできる
  • Vuetify の v-data-table をラップする際の強力なテクニック

同じように悩んだ人の助けになれば幸いです。