はじめに (対象読者・この記事でわかること)
この記事は、Web フロントエンドに興味がある初心者から中級者を対象にしています。
HTML と CSS の基本が理解できていれば、JavaScript のみで以下が実装できるようになります。
- テキスト入力欄に入力した文字をリアルタイムで別要素に反映させる
- フォーム送信後に「送信が完了しました」などのメッセージを表示する
- 基本的なエラーハンドリングと UI フィードバックを実装できる
背景として、ユーザー体験(UX)を向上させるために、入力中の即時フィードバックが重要視されています。今回の実装例は、シンプルなお問い合わせフォームを題材に、実践的なコードを書きながら学べる構成です。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML/CSS の基本的な知識
- JavaScript(ES6 以降)の文法が書けること
- ブラウザの開発者ツールの使い方が分かること
入力内容のリアルタイム反映と送信完了メッセージの概要
ユーザーがテキストエリアに入力した内容を、画面の別箇所に即座に表示させる「ライブプレビュー」機能は、現在入力中の情報を可視化できるため、入力ミスや認識のずれを防止します。
一方、フォーム送信後に表示する「送信完了メッセージ」は、操作が成功したことを明示し、次のアクションへ誘導する重要な UI パターンです。
本セクションでは、まず「リアルタイム反映」の仕組みを解説し、続いて「送信完了メッセージ」の実装フローを概観します。
- イベントリスナー:
inputイベントで入力内容を取得し、innerTextやtextContentに代入 - 非同期送信:
fetchAPI を利用してサーバーへデータを POST。成功時にメッセージを表示 - 状態管理:送信中・成功・エラーの各状態に応じて DOM を切り替える
この流れを押さえておけば、ほぼ任意のフォームに同様の機能を組み込むことが可能です。
実装手順とコード例
以下では、シンプルなお問い合わせフォームを例に、実装手順をステップごとに解説します。コードはすべて HTML、CSS、JavaScript のみで完結します。
ステップ1 - HTML の用意
Html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>お問い合わせフォーム</title> <style> body {font-family: sans-serif; margin: 2rem;} .preview {border: 1px solid #ccc; padding: .5rem; margin-top: .5rem;} .message {color: green; margin-top: 1rem; display:none;} .error {color: red; margin-top: 1rem; display:none;} </style> </head> <body> <h1>お問い合わせ</h1> <form id="contactForm"> <label> お名前: <input type="text" name="name" required> </label><br><br> <label> メッセージ: <textarea name="msg" rows="4" required></textarea> </label><br><br> <button type="submit">送信</button> </form> <h2>入力内容プレビュー</h2> <div class="preview" id="previewArea">ここに入力が表示されます</div> <div class="message" id="successMsg">送信が完了しました!</div> <div class="error" id="errorMsg">送信に失敗しました。再度お試しください。</div> <script src="app.js"></script> </body> </html>
#previewAreaがライブプレビュー表示領域です。#successMsgと#errorMsgは送信結果を示すメッセージ要素です。
ステップ2 - JavaScript でライブプレビュー実装
app.js というファイルに以下を記述します。
Js// 要素取得 const form = document.getElementById('contactForm'); const preview = document.getElementById('previewArea'); const successMsg = document.getElementById('successMsg'); const errorMsg = document.getElementById('errorMsg'); // 入力欄全体を監視 form.addEventListener('input', e => { const formData = new FormData(form); const name = formData.get('name') || ''; const msg = formData.get('msg') || ''; preview.innerHTML = `<strong>${escapeHTML(name)}</strong><br>${escapeHTML(msg)}`; }); // XSS 防止のためのエスケープ関数 function escapeHTML(str) { return String(str) .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }
inputイベントは、テキストフィールド・テキストエリアのどちらが変化しても発火します。FormDataを利用すれば、フォーム内の全入力値を簡潔に取得できます。escapeHTMLで文字列をサニタイズし、HTML インジェクションを防止しています。
ステップ3 - 非同期送信と完了メッセージ
続いて、submit イベントでサーバーへデータを送ります。今回はデモ用に https://httpbin.org/post を使用します。
Jsform.addEventListener('submit', async e => { e.preventDefault(); // 既定の送信をキャンセル // UI リセット successMsg.style.display = 'none'; errorMsg.style.display = 'none'; const payload = { name: form.elements.name.value, msg : form.elements.msg.value }; try { const response = await fetch('https://httpbin.org/post', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`HTTP ${response.status}`); // 送信成功時 successMsg.style.display = 'block'; form.reset(); // フォームをクリア preview.textContent = 'ここに入力が表示されます'; } catch (err) { console.error('送信エラー:', err); errorMsg.style.display = 'block'; } });
fetchのawaitで非同期処理を直感的に記述。response.okがfalseの場合は例外を投げ、catchブロックでエラーメッセージを表示。- 送信成功後はフォームをリセットし、プレビュー領域も初期状態に戻します。
ハマった点やエラー解決
| 現象 | 原因 | 解決策 |
|---|---|---|
| プレビューが更新されない | input イベントを <form> に付与したが、textarea の変化がキャッチできていなかった |
form.addEventListener('input', …) は子要素すべてに伝搬するので本来は動くが、<textarea> に name が抜けていると FormData で取得できず空文字になる。name="msg" を確認。 |
| 送信後にエラーメッセージが常に表示 | successMsg.style.display = 'none' を catch の外に書き忘れた |
送信開始時に成功・失敗メッセージを必ず非表示にリセットするコードを追加。 |
クロスオリジンで fetch が失敗 |
デモサーバーが CORS を許可していない | https://httpbin.org は CORS が有効。自前サーバーでテストする場合は Access-Control-Allow-Origin: * ヘッダーを設定するか、ローカルで json-server などを使用。 |
解決策(実装コードでのポイント)
- イベント伝搬を利用し、
formに一括でinputをリッスン。個別にaddEventListenerする手間が省けます。 - サニタイズは必ず行う。
escapeHTMLをユーティリティ関数化して再利用しやすくしました。 - 状態管理は
displayの切り替えだけでシンプルに。スケールアップ時はclassList.add/removeに置き換えて CSS アニメーションを付与すると更に UI が洗練します。
以上で、入力内容のリアルタイム反映と送信完了メッセージの基本実装が完了です。実際のプロジェクトでは、バリデーションライブラリや UI フレームワーク(React, Vue, Svelte など)に合わせて同様のロジックを組み込むことができます。
まとめ
本記事では、入力内容のライブプレビューと非同期送信後の完了メッセージ表示を、純粋な JavaScript とシンプルな HTML/CSS だけで実装する手順を解説しました。
- ライブプレビューは
inputイベントとFormDataで簡潔に実装 - 非同期送信は
fetch+async/awaitでエラーハンドリングも容易 - 状態管理は表示/非表示の切り替えだけで十分だが、拡張は
classListで可能
この記事を通して、ユーザー体験を向上させるインタラクティブなフォームの基本が身につき、実務でもすぐに応用できるでしょう。次回は、React/Vue で同様の機能をコンポーネント化する方法を紹介する予定です。
参考資料
- MDN Web Docs – FormData
- MDN Web Docs – fetch API
- MDN Web Docs – HTMLInputElement: input event
- httpbin.org – POST endpoint