【HTMLフォーム入門】お問い合わせフォームを作って入力チェックの入口を学ぶ
章: 2章
技術タグ: DevTools JavaScript UX バリデーション フォーム
今回やること
前回までのおみくじ編では、ブラウザ側の処理だけを信用してはいけないことを学びました。
ここからは、第2章のお問い合わせフォーム編に入ります。
フォームは、Web開発の基礎がかなり詰まっている題材です。
なぜなら、フォームではユーザーが自由にデータを入力して、こちらのシステムに送ってくるからです。
ユーザーが入力する ↓ ブラウザでチェックする ↓ サーバーへ送る ↓ サーバー側でもチェックする ↓ 保存・送信・表示する
今回はその入口として、HTMLでお問い合わせフォームを作り、JavaScriptで空欄チェックをします。
ただし、今回のJavaScriptチェックは最終防衛ラインではありません。
あくまで、ユーザーが入力ミスに気づきやすくするための入口です。
今回のゴール
今回のゴールは、以下です。
- HTMLでお問い合わせフォームを作る
- お名前・メールアドレス・お問い合わせ内容の入力欄を用意する
- CSSで最低限見やすく整える
- JavaScriptで送信時の空欄チェックをする
- 空欄があればエラーメッセージを表示する
- 問題なければ入力チェック通過メッセージを表示する
今回はまだPHPへ送信しません。
まずは、ブラウザ上で入力チェックをするところまでを体験します。
今回必要なもの
今回はHTML・CSS・JavaScriptだけで進めます。
そのため、PHPやLaragonはまだ必要ありません。
- VS Code
- Live Server
- Google Chrome
- Chrome DevTools
第2章の後半ではPHPやデータベースを使います。
しかし今回は、まずフォームの形とJavaScriptの入力チェックに集中します。
ファイル構成
今回のファイル構成は、以下です。
contact-form-app/ ├─ index.html ├─ style.css └─ script.js
| ファイル | 役割 |
|---|---|
| index.html | フォームの画面を作る |
| style.css | フォームの見た目を整える |
| script.js | 送信時の空欄チェックをする |
おみくじ編と同じように、HTML・CSS・JavaScriptの役割を分けて進めます。
フォームとは何か
フォームとは、ユーザーから入力を受け取るためのHTMLの仕組みです。
お問い合わせフォーム、ログインフォーム、会員登録フォーム、検索フォームなど、WebサイトやWebアプリの多くで使われています。
フォームでは、主に次のような部品を使います。
| 部品 | 役割 |
|---|---|
| form | 入力欄全体をまとめる |
| label | 入力欄の説明を書く |
| input | 1行の入力欄を作る |
| textarea | 複数行の入力欄を作る |
| button | 送信ボタンを作る |
今回作るお問い合わせフォームでも、これらを使います。
index.htmlを用意する
index.html を作成し、以下の内容を書きます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>お問い合わせフォーム</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
</head>
<body>
<main class="contact-page">
<h1 class="contact-page__title">お問い合わせフォーム</h1>
<p class="contact-page__lead">
ご質問やご相談があれば、以下のフォームから送信してください。
</p>
<form id="contact-form" class="contact-form" action="#" method="post" novalidate>
<div class="contact-form__field">
<label class="contact-form__label" for="name">お名前</label>
<input class="contact-form__control" type="text" id="name" name="name" />
<p id="name-error" class="contact-form__error" aria-live="polite"></p>
</div>
<div class="contact-form__field">
<label class="contact-form__label" for="email">メールアドレス</label>
<input class="contact-form__control" type="email" id="email" name="email" />
<p id="email-error" class="contact-form__error" aria-live="polite"></p>
</div>
<div class="contact-form__field">
<label class="contact-form__label" for="message">お問い合わせ内容</label>
<textarea class="contact-form__control contact-form__textarea" id="message" name="message"></textarea>
<p id="message-error" class="contact-form__error" aria-live="polite"></p>
</div>
<button class="contact-form__button" type="submit">
送信する
</button>
<p id="form-message" class="contact-form__message" aria-live="polite"></p>
</form>
</main>
</body>
</html>今回のHTMLでは、form の中に3つの入力欄を用意しています。
- お名前
- メールアドレス
- お問い合わせ内容
また、それぞれの入力欄の下に、エラーメッセージを表示するための p タグも用意しています。
name-error email-error message-error
JavaScriptでは、このエラー表示エリアにメッセージを入れていきます。
novalidateを付けている理由
今回の form には、novalidate を付けています。
<form id="contact-form" class="contact-form" action="#" method="post" novalidate>
novalidate は、ブラウザ標準の入力チェックを無効にする指定です。
普通はブラウザ標準のチェックも便利ですが、今回はJavaScriptで空欄チェックの仕組みを学びたいので、あえて無効化しています。
これにより、JavaScriptで自分たちが書いたチェック処理の動きがわかりやすくなります。
style.cssを用意する
次にCSSです。
今回の主役はフォームの入力チェックなので、見た目は作り込みすぎません。
ただし、色や余白を毎回バラバラの数値で書くと、あとから変更する時に面倒になります。
そこで今回は、簡易的なデザイントークンを用意します。
デザイントークンとは、色・余白・角丸などの値に名前を付けて管理する考え方です。
たとえば、毎回 #222222 や 24px と直接書く代わりに、--color-text や --space-l のような名前で扱います。
これは、あとから修正しやすくするための怠惰です。
同じ値を何度も探して直すのではなく、最初に名前を付けておき、変更箇所を減らします。
この連載では、ただ動くコードではなく、あとから見返して直しやすいコードも少しずつ意識していきます。
style.css に以下を書きます。
:root {
--color-bg: #f5f5f5;
--color-text: #222222;
--color-surface: #ffffff;
--color-border: #cccccc;
--color-error: #c0392b;
--space-s: 8px;
--space-m: 16px;
--space-l: 24px;
--space-xl: 32px;
--space-2xl: 64px;
--radius-m: 8px;
--radius-l: 16px;
--radius-pill: 999px;
--font-base: sans-serif;
}
body {
margin: 0;
font-family: var(--font-base);
background-color: var(--color-bg);
color: var(--color-text);
}
.contact-page {
max-width: 640px;
margin-inline: auto;
padding-block: var(--space-2xl);
padding-inline: var(--space-l);
}
.contact-page__title {
margin-block-start: 0;
margin-block-end: var(--space-m);
font-size: 32px;
text-align: center;
}
.contact-page__lead {
margin-block-start: 0;
margin-block-end: var(--space-xl);
line-height: 1.8;
text-align: center;
}
.contact-form {
display: grid;
gap: var(--space-l);
padding-block: var(--space-xl);
padding-inline: var(--space-l);
border-radius: var(--radius-l);
background-color: var(--color-surface);
}
.contact-form__field {
display: grid;
gap: var(--space-s);
}
.contact-form__label {
font-weight: bold;
}
.contact-form__control {
width: 100%;
padding-block: 12px;
padding-inline: 12px;
border-width: 1px;
border-style: solid;
border-color: var(--color-border);
border-radius: var(--radius-m);
font-size: 16px;
box-sizing: border-box;
}
.contact-form__textarea {
min-height: 160px;
resize: vertical;
}
.contact-form__error {
min-height: 1.5em;
margin-block-start: 0;
margin-block-end: 0;
color: var(--color-error);
font-size: 14px;
}
.contact-form__button {
padding-block: 14px;
padding-inline: var(--space-l);
border-width: 0;
border-radius: var(--radius-pill);
background-color: var(--color-text);
color: var(--color-surface);
font-size: 16px;
font-weight: bold;
cursor: pointer;
}
.contact-form__button:hover {
opacity: 0.8;
}
.contact-form__message {
margin-block-start: 0;
margin-block-end: 0;
font-weight: bold;
text-align: center;
}
今回のCSSで大事なのは、エラーメッセージを見やすくすることです。
.contact-form__error {
color: #c0392b;
}
フォームでは、ユーザーがどこを直せばいいのか分かることが重要です。
JavaScriptでフォームを取得する
ここからJavaScriptです。
まず、HTML上のフォームや入力欄、エラー表示エリアを取得します。
script.js の前半では、次のような要素を取得します。
- フォーム本体
- お名前の入力欄
- メールアドレスの入力欄
- お問い合わせ内容の入力欄
- 各エラーメッセージ表示エリア
- フォーム全体のメッセージ表示エリア
HTMLに付けた id を使って、JavaScriptから要素をつかまえます。
document.getElementById('contact-form');
document.getElementById('name');
document.getElementById('email');
document.getElementById('message');
送信時にJavaScriptを動かす
フォームには submit というイベントがあります。
これは、送信ボタンを押した時に発生するイベントです。
今回のコードでは、以下のように送信時の処理を登録します。
contactForm.addEventListener('submit', handleContactFormSubmit);
これにより、送信ボタンを押した時に handleContactFormSubmit() が実行されます。
event.preventDefault()で送信を止める
フォームは通常、送信ボタンを押すとページ遷移しようとします。
しかし今回は、まだPHPへ送信しません。
まずはJavaScriptで入力チェックをしたいので、通常の送信を止めます。
event.preventDefault();
event.preventDefault() は、ブラウザの標準動作を止めるための命令です。
今回の場合は、フォームの通常送信を一旦止めて、JavaScriptのチェック処理を先に動かします。
空欄チェックの考え方
今回の空欄チェックでは、入力値が空かどうかを確認します。
考え方はシンプルです。
入力値を取得する ↓ 前後の空白を取り除く ↓ 空文字ならエラーにする
前後の空白を取り除くために、trim() を使います。
nameInput.value.trim() === ''
これにより、スペースだけ入力された場合も空欄として扱えます。
script.jsを用意する
script.js に以下を書きます。
const contactForm = document.getElementById('contact-form');
const nameInput = document.getElementById('name');
const emailInput = document.getElementById('email');
const messageInput = document.getElementById('message');
const nameError = document.getElementById('name-error');
const emailError = document.getElementById('email-error');
const messageError = document.getElementById('message-error');
const formMessage = document.getElementById('form-message');
/**
* エラーメッセージをすべてリセットする
*
* @returns {void}
*/
function resetErrors() {
nameError.textContent = '';
emailError.textContent = '';
messageError.textContent = '';
formMessage.textContent = '';
}
/**
* お問い合わせフォームの入力内容をチェックする
*
* @returns {boolean} 入力内容が問題なければtrue、不足があればfalse
*/
function validateContactForm() {
let isValid = true;
if (nameInput.value.trim() === '') {
nameError.textContent = 'お名前を入力してください。';
isValid = false;
}
if (emailInput.value.trim() === '') {
emailError.textContent = 'メールアドレスを入力してください。';
isValid = false;
}
if (messageInput.value.trim() === '') {
messageError.textContent = 'お問い合わせ内容を入力してください。';
isValid = false;
}
return isValid;
}
/**
* フォーム送信時の処理
*
* @param {SubmitEvent} event 送信イベント
* @returns {void}
*/
function handleContactFormSubmit(event) {
event.preventDefault();
resetErrors();
const isValid = validateContactForm();
if (!isValid) {
formMessage.textContent = '入力内容を確認してください。';
return;
}
formMessage.textContent = '入力チェックを通過しました。';
}
contactForm.addEventListener('submit', handleContactFormSubmit);このコードでは、まずエラーメッセージをリセットし、そのあと入力内容をチェックしています。
空欄があれば、該当する入力欄の下にエラーメッセージを表示します。
問題がなければ、フォーム下部に「入力チェックを通過しました。」と表示します。
LG流:チェック処理は関数に分ける
今回のJavaScriptでは、処理をいくつかの関数に分けています。
| 関数 | 役割 |
|---|---|
| resetErrors() | エラーメッセージを消す |
| validateContactForm() | 入力内容をチェックする |
| handleContactFormSubmit() | フォーム送信時の全体処理を担当する |
全部を1つの場所に書くこともできます。
しかし、処理の役割を分けた方が、あとから読みやすくなります。
フォーム処理は今後、PHP送信やDB保存、fetch送信などに発展していきます。
そのため、最初から少しだけ責務を分けて書いておくと、あとで育てやすくなります。
実際に動かしてみる
Live Serverで index.html を開きます。
何も入力せずに「送信する」ボタンを押してみてください。
以下のようにエラーが表示されれば成功です。
- お名前を入力してください。
- メールアドレスを入力してください。
- お問い合わせ内容を入力してください。
- 入力内容を確認してください。
次に、すべての入力欄に文字を入れて送信してみます。
フォーム下部に「入力チェックを通過しました。」と表示されればOKです。
今回の入力チェックは防御ではなく補助
ここで大事な注意があります。
今回のJavaScriptによる空欄チェックは、ユーザーの入力ミスを減らすための補助です。
これだけでシステムを守れるわけではありません。
なぜなら、JavaScriptはブラウザ側で動くからです。
JavaScriptはユーザー側で見える JavaScriptは無効化される可能性がある DevToolsで書き換えられる可能性がある
つまり、JavaScriptの入力チェックは便利ですが、最終防衛ラインではありません。
本当に大事なチェックは、次回以降にPHP側でも行います。
今回わかったこと
今回は、HTMLでお問い合わせフォームを作り、JavaScriptで空欄チェックをしました。
学んだことは以下です。
- formで入力欄をまとめられる
- labelで入力欄の説明を書ける
- inputで1行入力欄を作れる
- textareaで複数行入力欄を作れる
- submitイベントで送信時の処理を動かせる
- event.preventDefault()で通常送信を止められる
- trim()で前後の空白を取り除ける
- JavaScriptでエラーメッセージを表示できる
- フロント側の入力チェックはユーザー補助であり、最終防衛ラインではない
フォーム処理は、Web開発の基礎がかなり詰まっています。
ここから、少しずつサーバー側の処理へ進んでいきます。
次回予告
次回は、今回作ったJavaScriptの空欄チェックをあえて突破してみます。
DevToolsを使ったり、ブラウザ側の処理を避けたりしながら、フロント側バリデーションだけでは守れないことを体験します。
次回のテーマは、以下です。
【JavaScriptバリデーションの罠】フロント側の入力チェックを突破してみる
フォームは、ユーザーが自由にデータを送ってくる入口です。
だからこそ、ブラウザ側だけではなく、サーバー側でも必ずチェックする必要があります。
次回は、その理由を実際に体験します。