`<wa-textarea>` の無効状態スタイリングを他フォームコントロールと統一

shoelace-style/webawesome

<wa-textarea>disabled 状態に視覚的スタイルが適用されていなかったバグを修正し、<wa-input><wa-select> など他のフォームコントロールと同等の外観を実現しました。

背景

<wa-textarea>disabled 属性で無効化しても、有効な状態と見た目が変わらないというバグが #2416 で報告されていました。他のフォームコントロールでは無効状態に明確な視覚的フィードバック(半透明表示やカーソル変更)が適用されているにもかかわらず、<wa-textarea> だけがその一貫性から外れていました。

ユーザーはフォームの送信可否やフィールドの操作可否をUIの見た目から判断します。無効フィールドが有効フィールドと区別できない状態は、アクセシビリティおよびユーザビリティ上の問題です。Issue では cursor: not-allowed の欠如と視覚的差異のなさが具体的に指摘されており、Firefox / Ubuntu 環境で確認されています。

技術的な変更

textarea.styles.ts に2か所の CSS 変更が加えられました。変更はいずれも既存のスタイル構造に自然に統合されており、影響範囲は <wa-textarea> コンポーネントのスタイルに限定されます。

1つ目は、コンテナ要素への :has(:disabled) セレクタの追加です。ラッパー要素に対して opacitycursor を適用することで、Shadow DOM 内部の <textarea> 要素が disabled になったときにコンポーネント全体の外観を制御します。

変更前:

&:focus-within {
  outline-color: var(--wa-color-focus);
}

変更後:

&:focus-within {
  outline-color: var(--wa-color-focus);
}

/* Style disabled textareas */
&:has(:disabled) {
  cursor: not-allowed;
  opacity: 0.5;
}

2つ目は、<textarea> 要素自体に cursor: inherit を追加する変更です。コンテナ側で設定した cursor: not-allowed を内側の <textarea> 要素が継承できるよう、明示的に inherit を指定しています。

変更後:

background: transparent;
font: inherit;
color: inherit;
cursor: inherit; /* 追加 */
padding: calc(var(--wa-form-control-padding-block) - ((1lh - 1em) / 2)) var(--wa-form-control-padding-inline);

この2段階の構成により、コンテナで not-allowed を宣言し、内側の <textarea> がそれを継承することで、コンポーネント全体にわたって一貫したカーソル表示が実現されます。

設計判断

:has(:disabled) セレクタをコンテナ側に適用する方式 が採用されました。<wa-textarea> は Shadow DOM を持つ Web Components であり、実際の <textarea> 要素はシャドウルート内に存在します。コンテナ側で :has(:disabled) を使うことで、内部の disabled 状態をコンポーネント全体のスタイルに反映できます。

opacity: 0.5cursor: not-allowed という値の選択は、他のフォームコントロール(<wa-input> など)との視覚的一貫性を意図したものです。コンポーネント間でスタイルの語彙を統一することは、デザインシステムの保守性に直結します。

また、cursor: inherit<textarea> に追加しない場合、ブラウザのデフォルトスタイルがコンテナの cursor 指定を上書きしてしまうため、この記述は省略できません。コンテナと内部要素の2点でスタイルを協調させることで、Shadow DOM を跨いだプロパティの伝播を確実にしています。

まとめ

:has(:disabled)cursor: inherit の組み合わせにより、Shadow DOM を持つ Web Components でもコンテナ起点でコンポーネント全体の無効状態を制御できることが示されました。この修正により、Web Awesome のフォームコントロール群における視覚的一貫性が回復し、disabled 状態のアフォーダンスが他コンポーネントと揃いました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
081d69af

この記事は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リンク記法の正確性

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

対象読者への適合性 ✓ PASS

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

Shadow DOM、`:has()`セレクタなどの用語を前提としており、専門知識を持つエンジニアという対象読者に適合した内容です。

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

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

各セクション・パラグラフが「総論→各論」の構造で書かれており、トピックセンテンスも明確です。1段落1トピックが守られており、非常に読みやすいです。

Diff内容との照合 ✓ PASS

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

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

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`:has(:disabled)`, `Shadow DOM`, `cursor: inherit` など、関連する技術用語を正確かつ適切な文脈で使用しています。

説明の技術的正確性 ✓ PASS

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

`cursor: inherit` がなぜ必要なのか、`:has()` をコンテナに適用する理由など、変更の技術的な背景と妥当性が論理的に説明されています。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのタイトル、Description、およびDiff内容から裏付けられます。Issueからの情報引用もPRの文脈上、妥当な範囲です。

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

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

PR番号(#2419)、Issue番号(#2416)などの固有名詞はすべて正確です。

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

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

記事のタイトルはPRの主題「`<wa-textarea>`の無効状態のスタイリング修正」を的確に要約しています。

外部知識の正確性 ✓ PASS

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

PRで言及されていない外部知識(LTS情報、リリース日など)の捏造はなく、PRの範囲内で解説が完結しています。

時間表現の正確性 ✓ PASS

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

過去のバグと今回の修正という時間的な関係性が正しく記述されており、時間表現の歪曲はありません。