開発者が見落としがちなネイティブHTMLバリデーション属性
フォームのバリデーションに、HTMLがネイティブで処理できるカスタムJavaScriptを書いていませんか。多くのフロントエンド開発者はrequiredやpatternを知っていますが、プラットフォームはそれ以上のものを提供しています。コードを削減し、アクセシビリティを向上させ、フレームワークに依存せずに優れたUXを実現する属性です。
この記事では、見落としている可能性が高いHTMLバリデーション属性と、ネイティブフォームバリデーションを本当に有用にするCSSおよびJavaScript機能について説明します。
重要なポイント
form属性により、コントロールをDOM位置に関係なくIDでフォームと関連付けることができ、複雑なラッパー構造が不要になります。formaction、formmethod、formnovalidateなどのボタンごとの属性により、単一のフォームを送信ボタンに応じて異なる動作にできます。- 最新の
autocompleteトークン(new-password、one-time-code、webauthn)は、オートフィルの精度を向上させ、パスワードジェネレーターなどのブラウザ機能をトリガーします。 - CSS
:user-invalidは、ユーザーの操作後にのみエラーを表示することで、「ページ読み込み時の赤い枠線」問題を解決します。 - Constraint Validation API(
setCustomValidity()、checkValidity()、reportValidity())は、ネイティブバリデーションに拡張が必要な場合にプログラム的な制御を提供します。
form属性:フォーム外のコントロール
ページヘッダーに送信ボタンが必要で、フォームがメインコンテンツにある場合はどうでしょうか。form属性により、DOM位置に関係なく、任意のコントロールをIDでフォームと関連付けることができます。
<form id="checkout">
<input type="email" name="email" required>
</form>
<button type="submit" form="checkout">購入を完了</button>
これにより、ラッパーの複雑な操作が不要になり、input、button、select、textareaで同様に機能します。
知っておくべきボタンごとのオーバーライド
単一のフォームは、どのボタンで送信されるかによって異なる動作をすることができます。これらの属性は親フォームの設定をオーバーライドします:
formaction— 異なるURLに送信formmethod— POSTの代わりにGETを使用(またはその逆)formenctype— ファイルアップロード用のエンコーディングを変更formtarget— 新しいタブでレスポンスを開くformnovalidate— バリデーションを完全にスキップ
formnovalidate属性は特に注目に値します。不完全なデータが許容される「下書き保存」ボタンには不可欠です。
有用なエラーメッセージを伴うパターンバリデーション
pattern属性は正規表現を受け入れますが、ブラウザはデフォルトで一般的なエラーを表示します。titleと組み合わせてコンテキストを提供します:
<input type="text"
pattern="[A-Z]{2}[0-9]{6}"
title="形式:2文字の英字の後に6桁の数字(例:AB123456)">
注意:type="email"などの入力でmultipleが設定されている場合、パターンはカンマ区切りの文字列全体ではなく、各個別の値に適用されます。
最新のautocompleteトークン
onとoff以外に、autocompleteはオートフィルの精度を向上させるセマンティックトークンを受け入れます:
autocomplete="new-password"— パスワードジェネレーターをトリガーautocomplete="one-time-code"— SMS認証用に最適化autocomplete="webauthn"— パスキー認証情報フィールドを示す
これらのトークンは摩擦を減らし、ブラウザやパスワードマネージャーに意図を伝えます(HTMLスペックとMDNのautocompleteドキュメントで完全なトークンリストを参照してください)。
国際化のためのdirname属性
右から左への言語をサポートする場合、dirnameは値と一緒にテキストの方向を自動的に送信します:
<input type="text" name="comment" dirname="comment.dir">
フォームはcomment(値)とcomment.dir(ltrまたはrtl)の両方を送信します。ユーザー生成コンテンツの適切なレンダリングに不可欠です。
Discover how at OpenReplay.com.
readonlyのニュアンス
よくある誤解:readonlyフィールドはフォーム送信に参加しますが、バリデーションとは異なる動作をします。値を送信し、フォーカスを受け取ることができます。
ただし、最新のHTMLではreadonlyコントロールは制約バリデーションから除外されます。つまり、現在の主要ブラウザでは、readonly入力に対してrequired、pattern、min、maxなどの属性はバリデーション目的で無視されます。
編集を許可せずに値を表示し、かつ送信しない場合は、disabledがより良い選択であることが多いです。ただし、無効化されたフィールドは値を送信しません。
最新のフォームUXのためのCSS :user-invalid
従来の:invalid疑似クラスは即座に発動し、ユーザーが操作する前にエラーを表示します。新しい:user-invalidはユーザーの操作後にのみマッチし、「ページ読み込み時の赤い枠線」問題を解決します。
input:user-invalid {
border-color: #dc3545;
}
input:user-valid {
border-color: #28a745;
}
これにより、JavaScriptのタイミングロジックなしでより良いUXを実現できます。主要ブラウザでのサポートは現在堅実です(MDNの:user-invalidを参照)。
Constraint Validation API
ネイティブバリデーションに拡張が必要な場合、Constraint Validation APIがプログラム的な制御を提供します:
checkValidity()— 真偽値を返し、失敗時にinvalidイベントを発火reportValidity()— 真偽値を返し、ネイティブエラーUIを表示setCustomValidity()— カスタムエラーメッセージを設定
const password = document.querySelector('#password');
const confirm = document.querySelector('#confirm');
confirm.addEventListener('input', () => {
confirm.setCustomValidity(
password.value !== confirm.value ? 'パスワードが一致する必要があります' : ''
);
});
エラーをクリアするにはsetCustomValidity('')を呼び出します。空でない文字列を渡すと、フィールドが無効としてマークされます。
ネイティブバリデーションが不十分な場合
ネイティブバリデーションはほとんどのケースを処理しますが、限界があります:
- クロスフィールドバリデーション(パスワード確認)にはJavaScriptが必要
- エラーメッセージのスタイリングはブラウザによって制御される
- 複雑な非同期バリデーション(ユーザー名の可用性)にはカスタムコードが必要
戦略:HTMLバリデーション属性をベースラインとして使用し、CSS :user-invalidでスタイルを設定し、必要な場合にのみConstraint Validation APIを追加します。
まとめ
ネイティブフォームバリデーションは大幅に成熟しました。ここで取り上げた属性—form、ボタンごとのオーバーライド、dirname、最新のautocompleteトークン—は、デフォルトでアクセシビリティを向上させながら、大量のカスタムJavaScriptを排除します。
既存のフォームを監査してください。HTMLがネイティブで処理するバリデーションロジックや、CSS :user-invalidが単一のイベントリスナーなしで解決するUX問題が見つかる可能性が高いでしょう。
よくある質問
ネイティブバリデーションエラーバブルには、ブラウザによって制御される限定的なスタイリングオプションがあります。CSSで直接スタイルを設定することはできません。カスタムスタイルのエラーメッセージを表示するには、フォームのnovalidate属性を使用して自動バリデーションUIを無効にし、Constraint Validation APIを使用して妥当性をチェックし、独自のエラー要素を表示できます。validationMessageプロパティを使用すると、ブラウザが生成したエラーテキストにアクセスできます。
はい、ネイティブバリデーション属性は標準HTMLをレンダリングするため、フレームワークで機能します。ただし、フレームワークは多くの場合、フォームの状態を異なる方法で管理するため、ネイティブバリデーションと競合する可能性があります。多くの開発者はnovalidate属性を使用し、フレームワークの状態を通じてバリデーションを処理します。ハイブリッドアプローチとして、コンポーネント内でConstraint Validation APIをプログラム的に活用することもできます。
両方のメソッドは、要素がバリデーション制約を満たしているかどうかを示す真偽値を返します。違いは副作用にあります:checkValidity()は失敗時にinvalidイベントのみを発火しますが、reportValidity()はブラウザのネイティブエラーメッセージUIも表示します。妥当性を静かにチェックしたい場合はcheckValidity()を使用し、ブラウザにユーザーへのエラーフィードバックを表示させたい場合はreportValidity()を使用します。
HTML属性のみを使用して2つのフィールドが一致することをバリデーションすることはできません。これにはJavaScriptが必要です。確認フィールドにinputイベントリスナーを追加し、値が異なる場合はエラーメッセージ、一致する場合は空文字列でsetCustomValidity()を呼び出すことで、Constraint Validation APIを使用します。これにより、カスタムロジックがネイティブバリデーションシステムと統合されます。
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.