`wa-tab-group` の `body` パートをスロット直接指定からラッパー `div` に変更
wa-tab-group の body CSS パートが <slot> 要素自体ではなく、スロットを内包する <div> ラッパーに移動されました。これにより、wa-dialog や wa-card と同じ構造に統一されます。
背景
wa-tab-group は従来、パネル領域を <slot part="body"> として直接スロット要素にパートを指定していました。一方、wa-dialog や wa-card では body パートをスロットの外側のラッパー要素に持つ設計を採用しており、コンポーネント間で構造の不一致が生じていました。
#2198 で wa-card が同様のリファクタリングを受けており、<slot part="body"> から <div part="body"><slot></slot></div> へと変更されています。本 PR はその流れを wa-tab-group にも適用し、コンポーネントライブラリ全体での構造的一貫性を実現します。
::part(body) セレクターはパート名が同じため、既存のテーマやスタイルカスタマイズはそのまま動作します。パートが「スロット要素」から「コンテナ div」に変わった点のみが差異です。
技術的な変更
マークアップ・内部クエリ・スタイルセレクターの3箇所が連動して変更されています。
マークアップの変更 (tab-group.ts)
render() メソッド内のパネル領域が、スロット要素に直接パートを指定する形式からラッパー div を用いる形式へ変わりました。
変更前:
<slot part="body" class="body" @slotchange=${this.syncTabsAndPanels}></slot>
変更後:
<div part="body" class="body"><slot @slotchange=${this.syncTabsAndPanels}></slot></div>
内部クエリの変更 (tab-group.ts)
@query デコレーターのターゲットが .body(スロット要素)から .body slot(ラッパー内のスロット要素)へ変更され、プロパティ名も body から defaultSlot にリネームされました。これに伴い、getAllPanels() メソッドも this.defaultSlot.assignedElements() を参照するよう更新されています。公開 API(<wa-tab-panel> を配置するデフォルトスロット)は変わりません。
スタイルセレクターの変更 (tab-group.styles.ts)
wa-tab-panel へのパディング指定が、4方向(top・bottom・start・end)すべてで更新されています。
変更前:
.tab-group-top ::slotted(wa-tab-panel) { --padding: var(--wa-space-xl) 0; }
.tab-group-bottom ::slotted(wa-tab-panel) { --padding: var(--wa-space-xl) 0; }
.tab-group-start ::slotted(wa-tab-panel) { --padding: 0 var(--wa-space-xl); }
.tab-group-end ::slotted(wa-tab-panel) { --padding: 0 var(--wa-space-xl); }
変更後:
.tab-group-top .body slot::slotted(wa-tab-panel) { --padding: var(--wa-space-xl) 0; }
.tab-group-bottom .body slot::slotted(wa-tab-panel) { --padding: var(--wa-space-xl) 0; }
.tab-group-start .body slot::slotted(wa-tab-panel) { --padding: 0 var(--wa-space-xl); }
.tab-group-end .body slot::slotted(wa-tab-panel) { --padding: 0 var(--wa-space-xl); }
セレクターに .body slot を挟むことで、ラッパー経由の ::slotted() として正しく機能します。
設計判断
スロット要素をパート指定の対象から外す方針 が、コンポーネントライブラリ全体で統一されています。
Web Components において ::slotted() はスロットに割り当てられた直接の子要素にしか適用できません。スロット自体にレイアウト役割(display、padding 等)を持たせると、スロット要素のデフォルト display 値(contents 相当)との干渉が起きやすく、アクセシビリティ上も意図しない影響を与える可能性があります。ラッパー div を挟む構造にすることで、コンテナとしての CSS 制御がスロット要素に依存しなくなります。
また、::part(body) のパート名を維持したまま対象要素のみを切り替えているため、テーマ作成者への影響は最小限です。スロット要素より div の方が display や box model の制御が直感的であり、スタイルのカスタマイズ容易性も向上します。
まとめ
本 PR は wa-card での変更に続き、wa-tab-group の body パートをコンテナ div に統一した変更です。::part(body) の名称を保ちつつ対象要素を div ラッパーへ移すことで、公開 API の互換性を維持しながら wa-dialog・wa-card と同一の構造パターンを確立しています。