:has() で必須フォームのエラー演出

便利系 Medium #css #has-selector #form #validation

CSS :has() セレクタを活用し、HTML5 の :valid / :invalid 疑似クラスとと組み合わせて、JavaScript ゼロでフォーム入力状態に応じた装飾・送信ボタンの活性化を実現する。

▶ プレビュー

解説

:has() で必須フォームのエラー演出は、便利系カテゴリの「has-selector」に分類される実装パターンです。CSS のみで構成され、難易度は中級レベル。

HTML5 標準の :valid / :invalid 疑似クラスと :has() セレクタを組み合わせると、JavaScript を一切書かずに「入力状態に応じてフォーム全体の装飾を変える」ことができます。

このサンプルでは、各フィールドのバリデーション状態に応じて緑(OK)/ 赤(NG)に切り替え、すべての必須項目が valid のときだけ送信ボタンを活性化する処理を、純粋な CSS だけで実装しています。React や Vue のフォームライブラリを使わない静的ページでも、UX の高いフォームを作れます。

仕組み

下記コードタブから HTML / CSS をそれぞれ確認・コピーできます。プレビュー領域では実際の動作をその場で確認可能です。

CSS プロパティだけで完結しているため、フレームワーク非依存・軽量に組み込めます。React / Vue / Astro / 静的 HTML どれにも持ち込み可能です。

注意点 / カスタマイズ時のポイント

:placeholder-shown を使って「未入力状態は invalid 表示しない」工夫をしています。プレースホルダー(placeholder=" " の半角スペース)が必須なので、HTML 側を必ず合わせてください。

JavaScript なしで送信処理を完全に止めることはできないので、サーバーサイドでの最終バリデーションは別途必須です。

よくある質問

JavaScript でカスタムバリデーション(パスワード強度など)を入れたい場合は?
:invalid は HTML5 標準の required / type="email" / minlength / pattern のみ反応します。独自ルールは JS で setCustomValidity() を呼び出すと :invalid に組み込めます。
送信ボタンに :has() を使う部分の意味は?
「親要素 .hf に :invalid の入力が含まれていない」状態のときだけ送信ボタンを活性化する条件です。.hf:not(:has(input:invalid)) button と書いています。
このスニペットは商用利用できますか?
はい。moatway がオリジナルで制作したスニペットは商用・個人問わず自由にご利用いただけます。クレジット表記も不要です。
そのまま貼り付ければ動きますか?
はい。HTML / CSS / JS タブのコードをそれぞれ自分のファイルにコピーして貼り付ければ動きます。クラス名が他の CSS と衝突しないよう、必要に応じてリネームしてください。
ブラウザ対応は?
最新 2 世代の Chrome / Safari / Firefox / Edge で動作確認しています。Internet Explorer はサポート対象外です。
Tailwind CSS でも実装できますか?
可能です。クラスベースのスタイルを Tailwind のユーティリティクラスに置き換えれば同じ動作になります。アニメーション・疑似要素については @apply や arbitrary values が必要な場合があります。
inspired by 2026 modern CSS / Web APIs / 追加日:2026-05-13
← すべてのスニペットへ戻る