`<wa-badge>` の `role` 属性をスロットから移動し、スロットをラップ要素で包む

shoelace-style/webawesome

<wa-badge> コンポーネントで <slot> 要素に誤って付与されていた role="status" を仕様準拠の構造に修正しました。HTML仕様では <slot> への role 属性の付与は許可されていないため、各スロットを <span> でラップする構造に変更しています。

背景

#2163 で報告されたとおり、<slot> 要素への role 属性の付与はHTML仕様上、許可されていません。MDN の <slot> 技術仕様サマリーによれば、<slot> に付与できる属性は限定されており、ARIAロールはその対象外です。

従来の実装では、バッジのベーススロットに role="status" を直接付与していました。これはスクリーンリーダーなどの支援技術に対してライブリージョンとしてのセマンティクスを伝えることを意図した設計でしたが、<slot> はShadow DOMのコンテンツ投影機構であり、通常のHTMLフロー要素と同様のARIA属性の意味論を持ちません。

Issueでは role="status" もしくは aria-live="polite"<wa-badge> ホスト要素自体に付与する方法が代替案として提案されていましたが、今回の修正では <span> ラッパーを挟む方式が採用されています。

技術的な変更

badge.tsrender() メソッドにおいて、すべてのスロットが <span> 要素でラップされ、rolepart はラッパー側に移動しました。

変更前:

render() {
  return html`
    <slot name="start" part="start"></slot>

    <slot part="base" role="status"></slot>

    <slot name="end" part="end"></slot>
  `;
}

変更後:

render() {
  return html`
    <span part="start">
      <slot name="start"></slot>
    </span>

    <span part="base" role="status">
      <slot></slot>
    </span>

    <span part="end">
      <slot name="end"></slot>
    </span>
  `;
}

各スロットが <span> でラップされ、part 属性はラッパー側に付与されています。また、role="status" はベーススロットから対応する <span> に移動しており、HTMLの仕様に適合した構造になっています。

part 属性の付与先が <slot> から <span> に変わったことで、CSSパーツセレクタ(::part(base) 等)でスタイルを当てているユーザーは対象要素の型が変わる点に注意が必要です。ただし、セレクタ名自体は変更されていないため、通常のスタイリングには影響しません。

設計判断

<span> ラッパーを挟む方式 が採用され、role をホスト要素に移動する案は選択されていませんでした。

Issueではホスト要素 <wa-badge> への role 付与も提案されていましたが、今回の修正はWebAwesomeのコンポーネント実装規約(「slots per the WA convention」)に沿ったラップ構造の統一を優先しています。<span> を挟むことで、rolepart をShadow DOM内の具体的なレイアウト要素に紐付けつつ、<slot> 自体は純粋なコンテンツ投影の役割に限定する設計になっています。

このアプローチはstart・base・endの3スロット全てに対して一貫して適用されており、ラッパー要素の有無による構造的なばらつきをなくしています。

まとめ

本PRは仕様違反のマークアップを修正しながら、コンポーネント内部の構造をWebAwesomeの規約に沿って統一した変更です。<slot> を純粋なコンテンツ投影機構として扱い、ARIA属性やCSSパーツはラッパー要素側に集約するパターンは、Shadow DOMを用いたコンポーネント設計における明快な指針を示しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
6d15733f

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「リード文→背景→技術詳細→設計判断→まとめ」という総論→各論→結論の構成が明確で、ガイドラインに完全に準拠しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト、GitHubのIssue/PRへのリンク記法ともに正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Shadow DOM、slot、role、partといった専門用語を適切に用いており、専門知識を持つエンジニアという対象読者に適合した内容です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。非常に読みやすい構造です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されている変更前後のコードは、提供されたDiff情報と完全に一致しています。ファイル名も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`<slot>`, `role`, `part`, `Shadow DOM`, `ホスト要素`などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

`<slot>`に`role`を付与できないという仕様上の制約や、`part`属性の移動による影響など、技術的な説明は正確かつ論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのTitle, Description, Diff、または関連するIssueの情報によって裏付けられており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2220)やIssue番号(#2163)などの数値・固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRのタイトル「Wrap badge slots and fix invalid role」の内容を忠実に反映しており、主題のズレはありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

MDNへの言及は、PRの変更理由である「仕様違反」を補足するための適切な引用であり、PRにない情報を捏造するものではありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「従来の実装」や「今回の修正」といった時間表現は、変更の前後関係を正しく伝えており、PR情報と一致しています。