サブメニューが開いた状態のドロップダウン項目に選択状態のスタイルを適用

shoelace-style/webawesome

<wa-dropdown-item> でサブメニューが開いている際、ホバー時と同じ視覚的フィードバックが表示されない問題が修正されました。キーボード操作でサブメニューを開いた場合でも、ポインター操作と一貫した選択状態が表示されるようになります。

背景

キーボードナビゲーションとポインターナビゲーションの間で、サブメニューを持つドロップダウン項目の視覚的フィードバックに不一致がありました。ポインターでホバーしてサブメニューを開くと選択状態のスタイルが適用されていた一方、キーボード操作でサブメニューを開いた場合はその視覚的インジケーターが表示されませんでした。

#2279 では、この問題がユーザーにとってサブメニューが開いているかどうかを判別しにくいUX上の問題として報告されています。キーボードユーザーは開いたサブメニューの親項目がどれかを視覚的に確認できない状態でした。

アクセシビリティの観点からも、操作手段によらず一貫した視覚的フィードバックを提供することは重要であり、本修正はその一貫性を担保するものです。

技術的な変更

dropdown-item.styles.ts に2箇所のCSSルールが追加され、submenu-open というカスタム状態(CSS Custom State)を持つホスト要素に選択スタイルが適用されるようになりました。

変更前(サブメニューが開いた状態への選択スタイルなし):

:host(:focus-visible) {
  z-index: 1;
  outline: var(--wa-focus-ring);
  ...
}

:host([variant='danger']:focus-visible) {
  background-color: var(--wa-color-danger-fill-normal);
  color: var(--wa-color-danger-on-normal);
}

変更後(:state(submenu-open) への選択スタイルを追加):

:host(:state(submenu-open)) {
  background-color: var(--wa-color-neutral-fill-normal);
}

:host([variant='danger']:state(submenu-open)),
:host([variant='danger']:focus-visible) {
  background-color: var(--wa-color-danger-fill-normal);
  color: var(--wa-color-danger-on-normal);
}

追加されたルールは2点です。デフォルト状態では :host(:state(submenu-open))--wa-color-neutral-fill-normal の背景色を適用し、danger バリアントでは既存の :focus-visible セレクターと同じルールブロックに :state(submenu-open) を追加することで、危険な操作を示す項目にも対応しています。

設計判断

CSS Custom State(:state() を用いてコンポーネントの内部状態をスタイリングに反映する既存のパターンを踏襲した変更です。

Web Componentsでは ElementInternals.states を通じてカスタム状態を定義し、CSS側から :state() 擬似クラスで参照できます。本変更では submenu-open という状態が既にコンポーネント側で管理されており、スタイル側にそれに対応するCSSルールを追加するだけで完結しています。JavaScriptロジックの変更が不要だった点は、既存の状態管理設計が適切に機能していたことを示しています。

danger バリアントのセレクターは :state(submenu-open):focus-visible をカンマ区切りで並記する形を採用しており、同じ視覚スタイルを持つ両状態を1つのルールブロックにまとめることでコードの重複を避けています。

まとめ

本修正は、CSS Custom Stateという既存の仕組みを活用して、操作手段に依存しない一貫した視覚フィードバックを最小限のコード変更で実現しています。コンポーネントの状態管理とスタイリングが適切に分離されていたことで、スタイルのみの変更として問題を解決できた点が特筆されます。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
671b6e3f

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

「リード文(総論)→背景・技術的な変更・設計判断(各論)→まとめ(結論)」という理想的な3部構成が明確に適用されています。各セクションの役割も適切です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```typescript:path/to/file.ts)とGitHubリンク記法([#2279])がガイドライン通りに正しく使用されています。

対象読者への適合性 ✓ PASS

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

Web ComponentsやCSS Custom Stateといった専門用語を適切に使用しており、専門知識を持つエンジニアという対象読者に完全に適合しています。

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

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

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

Diff内容との照合 ✓ PASS

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

Diffの内容を正確に引用しています。変更前のコードも文脈理解のために提示されており、変更点が分かりやすく示されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「CSS Custom State」「ElementInternals.states」「:state()擬似クラス」などの技術用語が文脈に応じて正確に使用されています。

説明の技術的正確性 ✓ PASS

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

CSSセレクターの追加がどのように問題を解決するかの説明は、Diffのコード変更と完全に一致しており、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのDescription、Diff内のコード、または関連Issue番号によって裏付けられており、ハルシネーション(捏造)は見られません。

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

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

PR番号(#2316)およびIssue番号(#2279)がPR情報と正確に一致しています。

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

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

記事のタイトルはPRのタイトル「Fix submenu selection styles」の内容をより具体的に表現しており、主題は完全に一致しています。

外部知識の正確性 ✓ PASS

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

PR情報に含まれない外部知識(バージョンのサポート状況、リリース日程など)の捏造はなく、技術仕様の一般的な解説に留まっています。

時間表現の正確性 ✓ PASS

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

「既に」「まもなく」といった時間表現の歪曲はなく、事実を客観的に記述しています。