はじめに
今年ももう終わりですね〜、皆様はどんな一年だったでしょうか。 どうも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 をラップする際の強力なテクニック
同じように悩んだ人の助けになれば幸いです。