MENU

JavaScriptフォーム入力チェック入門:必須項目と文字数を実務で扱う基本

JavaScriptフォーム入力チェック入門:必須項目と文字数を実務で扱う基本

JavaScriptフォーム入力チェック入門:必須項目と文字数を実務で扱う基本

問い合わせフォームや資料請求フォームでは、送信前に「名前が空ではないか」「問い合わせ内容が長すぎないか」を確認できると、入力ミスをその場で直してもらえます。

結論から言うと、まず HTML の requiredmaxlength で最低限の制約を付け、足りない案内や文字数表示を JavaScript で補うのが扱いやすい方法です。JavaScript だけで全部を作るより、ブラウザ標準のフォーム検証を土台にしたほうが、少ないコードで安定します。

この記事では、必須項目と文字数確認に絞って、実務で使える最小構成を整理します。

  • HTML だけでできる必須チェックと文字数制限
  • JavaScript でエラーメッセージや文字数カウンターを出す方法
  • 入力例、出力例、よくある失敗
  • サーバー側チェックも必要になる理由
目次

前提環境:ブラウザ標準の検証機能を使う

この記事の例は、通常の HTML、CSS、JavaScript で動きます。React や Vue などのフレームワークは使いません。

確認時点は 2026年7月7日 です。フォーム検証の基本は HTML の制約検証、つまり Constraint Validation API を使います。MDN でも、HTML 属性による検証を土台にし、必要に応じて JavaScript で補う考え方が説明されています。

今回使う主な要素は次のとおりです。

  • required: 入力必須にする
  • maxlength: 入力できる最大文字数を決める
  • checkValidity(): フォーム全体が妥当か JavaScript から確認する
  • setCustomValidity(): 独自のエラーメッセージを設定する
  • input イベント: 入力中に文字数やエラー表示を更新する

ここがポイント: フォーム入力チェックは「送信を止める仕組み」だけではありません。ユーザーが何を直せばよいかを、送信前に分かるようにするためのものです。

HTMLだけでできる基本チェック

必須項目と文字数制限は、最初から JavaScript で書かなくても実現できます。

まずは HTML に制約を書きます。

<form id="contactForm" action="/contact" method="post">
  <div>
    <label for="name">お名前</label>
    <input id="name" name="name" type="text" required maxlength="30">
  </div>

  <div>
    <label for="message">お問い合わせ内容</label>
    <textarea id="message" name="message" required maxlength="200"></textarea>
  </div>

  <button type="submit">送信する</button>
</form>

この時点で、ブラウザは次のように動きます。

  • name が空のまま送信されそうになると、送信を止める
  • message が空のまま送信されそうになると、送信を止める
  • maxlength="200" を超える文字は、多くのブラウザで入力しにくくなる

入力例と期待される動き

例えば、次の状態で送信ボタンを押したとします。

お名前: 空欄
お問い合わせ内容: 見積もりについて相談したいです。

期待される動きは、フォーム送信が止まり、名前欄に入力を求めるブラウザ標準のメッセージが表示されることです。

HTML だけでも最低限の保護はできます。ただし、ブラウザ標準メッセージは文言や表示位置を細かく制御しにくいため、実務では JavaScript で補助表示を入れる場面が多くあります。

JavaScriptで必須項目と文字数を見やすくする

JavaScript を使う主な理由は、入力中のフィードバックを分かりやすくするためです。

ここでは、次の機能を追加します。

  • 未入力なら項目下にエラーを表示する
  • 文字数をリアルタイムに表示する
  • 送信時に不正な入力があれば送信を止める

HTML:エラー表示用の領域を用意する

<form id="contactForm" action="/contact" method="post" novalidate>
  <div class="field">
    <label for="name">お名前 <span aria-hidden="true">*</span></label>
    <input id="name" name="name" type="text" required maxlength="30" aria-describedby="nameError">
    <p id="nameError" class="error" aria-live="polite"></p>
  </div>

  <div class="field">
    <label for="message">お問い合わせ内容 <span aria-hidden="true">*</span></label>
    <textarea id="message" name="message" required maxlength="200" aria-describedby="messageError messageCount"></textarea>
    <p id="messageError" class="error" aria-live="polite"></p>
    <p id="messageCount" class="count">0 / 200</p>
  </div>

  <button type="submit">送信する</button>
</form>

novalidate は、ブラウザ標準のエラー吹き出しを出さず、JavaScript 側の表示に寄せたいときに使います。標準表示を使いたい場合は外して構いません。

JavaScript:送信時と入力中にチェックする

const form = document.querySelector('#contactForm');
const nameInput = document.querySelector('#name');
const messageInput = document.querySelector('#message');

const nameError = document.querySelector('#nameError');
const messageError = document.querySelector('#messageError');
const messageCount = document.querySelector('#messageCount');

function validateRequired(input, errorElement, label) {
  const value = input.value.trim();

  if (value === '') {
    errorElement.textContent = `${label}を入力してください。`;
    input.setAttribute('aria-invalid', 'true');
    return false;
  }

  errorElement.textContent = '';
  input.removeAttribute('aria-invalid');
  return true;
}

function updateMessageCount() {
  const max = Number(messageInput.getAttribute('maxlength'));
  const length = messageInput.value.length;
  messageCount.textContent = `${length} / ${max}`;

  if (length > max) {
    messageError.textContent = `${max}文字以内で入力してください。`;
    messageInput.setAttribute('aria-invalid', 'true');
    return false;
  }

  return true;
}

nameInput.addEventListener('input', () => {
  validateRequired(nameInput, nameError, 'お名前');
});

messageInput.addEventListener('input', () => {
  validateRequired(messageInput, messageError, 'お問い合わせ内容');
  updateMessageCount();
});

form.addEventListener('submit', (event) => {
  const isNameValid = validateRequired(nameInput, nameError, 'お名前');
  const isMessageRequiredValid = validateRequired(messageInput, messageError, 'お問い合わせ内容');
  const isMessageLengthValid = updateMessageCount();

  if (!isNameValid || !isMessageRequiredValid || !isMessageLengthValid) {
    event.preventDefault();
  }
});

このコードでは、空白だけの入力を未入力として扱うために trim() を使っています。問い合わせフォームでは、半角スペースだけで送信されても意味がないためです。

一方で、パスワード欄のように空白も意味を持つ可能性がある入力では、安易に trim() しないほうがよい場合もあります。

入力例と出力例で動きを確認する

フォーム検証は、コードを見ただけでは抜け漏れに気づきにくい部分です。最低限、次のパターンを手元で試すと動きが確認しやすくなります。

例1:お名前が空欄

入力:

お名前: 空欄
お問い合わせ内容: 料金について相談したいです。

表示されるメッセージ:

お名前を入力してください。

この場合、送信は止まります。ユーザーはどの項目を直せばよいかすぐ分かります。

例2:お問い合わせ内容が空欄

入力:

お名前: 山田太郎
お問い合わせ内容: 空欄

表示されるメッセージ:

お問い合わせ内容を入力してください。

必須項目のエラーは、送信ボタン付近だけにまとめるより、該当する入力欄の近くに出すほうが見落とされにくくなります。

例3:お問い合わせ内容の文字数を確認する

入力中の表示:

57 / 200

残り文字数を表示したい場合は、次のように変えられます。

function updateMessageCount() {
  const max = Number(messageInput.getAttribute('maxlength'));
  const length = messageInput.value.length;
  const remaining = max - length;
  messageCount.textContent = `残り${remaining}文字`;

  return remaining >= 0;
}

通常の問い合わせフォームなら 57 / 200 のような形式で十分です。SNS投稿欄や申請理由のように上限を強く意識して書く入力欄では、残り文字数のほうが親切な場合があります。

checkValidity() を使う書き方もある

フォーム全体の妥当性をまとめて確認したい場合は、checkValidity() が使えます。

例えば、HTML の requiredmaxlength を設定したうえで、送信前にフォーム全体を判定するなら次の形です。

form.addEventListener('submit', (event) => {
  if (!form.checkValidity()) {
    event.preventDefault();
    form.reportValidity();
  }
});

checkValidity() は、フォーム内の各入力欄が制約を満たしているかを返します。reportValidity() は、満たしていない場合にブラウザ標準のエラーメッセージ表示を促します。

どちらを使い分けるか

用途別に見ると、次のように考えると分かりやすいです。

方法 向いている場面 注意点
HTML属性だけ 簡単なフォーム、社内ツール、まず動かしたい画面 表示文言や見た目の調整に限界がある
HTML属性 + JavaScript 問い合わせフォーム、LP、WordPressテーマ内のフォーム HTML側の制約とJS側の条件をずらさない
JavaScript中心 複雑な条件分岐、入力内容によって必須項目が変わる画面 保守が難しくなりやすい

初心者向けの実務では、HTML属性 + JavaScriptの補助から始めるのが現実的です。HTMLに制約が残るため、あとからコードを読む人も条件を把握しやすくなります。

よくある失敗と直し方

フォーム入力チェックで多い失敗は、複雑なロジックよりも基本の抜けです。

失敗1:送信時だけチェックして入力中の案内がない

送信ボタンを押すまで何も表示されないフォームは、長文入力で不親切になりがちです。

特に文字数制限がある場合、送信後に「長すぎます」と言われると、ユーザーはどこまで削ればよいか分かりません。文字数カウンターを入力中に出しておくと、修正の手間を減らせます。

失敗2:maxlength と JavaScript の上限が違う

次のような状態は避けます。

<textarea maxlength="200"></textarea>
const maxLength = 300;

HTML では 200 文字、JavaScript では 300 文字として扱うと、どちらが正しい仕様なのか分からなくなります。上限値は HTML から取得するか、定数を一か所にまとめます。

const maxLength = Number(messageInput.getAttribute('maxlength'));

失敗3:クライアント側チェックだけで安全だと思う

ブラウザ上の JavaScript は、利用者側で無効化されたり、送信リクエストを直接作られたりする可能性があります。

そのため、入力チェックは次の2段構えで考えます。

  • クライアント側: 入力ミスをその場で直してもらうため
  • サーバー側: 不正なデータを保存・処理しないため

問い合わせフォームなら、サーバー側でも必須項目、文字数、メールアドレス形式、禁止文字、スパム対策などを確認します。JavaScript は使いやすさのため、サーバー側検証は安全性とデータ品質のために必要です。

WordPressで使うときの注意点

WordPress でフォーム周りの JavaScript を書く場合は、テーマやプラグインとの役割分担を確認します。

Contact Form 7、MW WP Form、独自テーマのフォームなど、環境によって送信処理の持ち方が違います。すでにプラグイン側でバリデーションがあるなら、JavaScript は文字数表示や入力補助に留めるほうが保守しやすいことがあります。

最低限、次の点を確認してください。

  • フォームの idclass が他ページと重複していないか
  • JavaScript が対象フォーム以外にも効いていないか
  • プラグイン側のエラー表示と二重になっていないか
  • サーバー側の必須チェックや文字数チェックが残っているか
  • 個人情報をブラウザのコンソールに出力していないか

特に問い合わせ内容やメールアドレスを console.log() で出すコードは、検証後に消しておきます。開発中の確認には便利ですが、公開サイトに残す必要はありません。

代替手段:HTML、ライブラリ、サーバー側の使い分け

フォーム検証は JavaScript だけで完結させるものではありません。画面の規模や運用体制で選び方が変わります。

  • 小さなフォーム: HTML属性 + 少量の JavaScript
  • 入力項目が多い管理画面: フレームワークやフォームライブラリ
  • 会員登録や決済に関わるフォーム: クライアント側 + サーバー側の厳密な検証
  • WordPressプラグインのフォーム: プラグイン標準機能を優先し、足りない表示だけ補う

見落とされがちなのは、入力チェックの目的が1つではない点です。ユーザーの入力ミスを減らす目的と、不正なデータを受け付けない目的は分けて考えます。

前者は JavaScript が得意です。後者はサーバー側で必ず扱います。

実装前のチェックリスト

最後に、実務で入れる前の確認点を短くまとめます。

  • 必須項目には HTML の required を付けたか
  • 文字数制限には maxlength を付けたか
  • JavaScript の上限値が HTML とずれていないか
  • 空白だけの入力をどう扱うか決めたか
  • エラーメッセージは入力欄の近くに出るか
  • 送信時だけでなく、入力中にも必要な案内が出るか
  • サーバー側でも同じ条件を検証しているか
  • 個人情報をログやコンソールに残していないか

フォーム入力チェックは、最初から大きな仕組みにする必要はありません。まずは HTML の制約で土台を作り、JavaScript で「どこを直せばよいか」を見えるようにする。そこまでできれば、問い合わせフォームやWordPressサイトの簡単な入力画面では十分に実用的です。

次に見るべき分岐点は、条件が増えたときです。「会社名は法人問い合わせのときだけ必須」「添付ファイルがあるときだけ説明文を必須」など、入力内容によってルールが変わり始めたら、フォーム全体の設計を見直すタイミングです。

参照リンク

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次