AJAXの問い合わせフォーム

同じ問い合わせ項目を fetch で JSON 送信します。訪問者はページに残り、短い状態表示を見ます。

コピーする内容

このスターターは、同じ問い合わせ項目を fetch で送ります。訪問者はページに留まり、短い状態表示を読みます。

フォームには、これまでどおり action と method POST があります。JavaScript が動かない場合、ブラウザは通常の送信を行います。

この代替経路は、古いブラウザや、スクリプトを止める人のために必要です。フォームを二つ保守する必要はありません。

主となるスニペットは JSON を送ります。Content-Type を application/json に、Accept を application/json に設定します。

成功は JSON の論理値 success です。それが true のとき、スニペットは応答メッセージ、または短い礼状を表示し、フォームをリセットします。

false のときは、スニペットが応答メッセージを表示します。Formgong はそのメッセージを _lang の言語で書きます。

JSON と FormData

JSON の本文には、送りたいフィールドを列挙する必要があります。スニペットには access_key、_lang、name、email、phone、message、botcheck が含まれます。

あとから Turnstile のコメントを外すと、JSON の経路は、その欄に値があるとき cf-turnstile-response もコピーします。

追加スニペットは JSON の代わりに FormData を使います。コンテンツタイプは、境界を含めてブラウザが設定します。Content-Type は自分で設定しないでください。

FormData はフォーム内のすべての欄を拾います。ウィジェットがフォームの中にあれば、Turnstile のトークンも含みます。

どちらの経路も Accept: application/json を送ります。このヘッダーがないと、ブラウザの通常のフォーム送信は JSON ではなくサンクスページを受け取ります。

JSON の本文と multipart の本文を同時に送らないでください。どちらか一方を選んでください。二つのスニペットは代替であり、重ねるものではありません。

スパム、Telegram、上限

ハニーポットの名前は botcheck のまま、空で、画面の外に、tabindex -1 で置いてください。埋まったハニーポットはスパムとして保存され、配信されません。

Telegram が太字で表示できるよう、フィールド名は短く保ってください。email を長い文に改名しないでください。

アクセスキーはページに残します。サーバーの秘密へ移してもフォームは安全になりません。このスニペットにサーバーはありません。

無料プランでは Telegram はすぐ届き、メールは日次ダイジェストです。受信箱は送信を 30 日保持します。

無料プランには月 300 件の送信が含まれます。スパムの送信は、そのうちの 1 件を使いません。

このプレビューは送信しません。スニペットを自分のサイトへつなぎ、そのページからテストを送ってください。

サービスを運営しているのは Formgong です。製品についての問い合わせは support@formgong.com へお書きください。

プレビュー

フォームのコード

HTML
<form id="fg-ajax" action="https://formgong.com/submit" method="POST" style="position:relative">
  <input type="hidden" name="access_key" value="fk_your_access_key">
  <input type="hidden" name="_lang" value="ja">
  <label>お名前 <input type="text" name="name" autocomplete="name" required></label>
  <label>メールアドレス <input type="email" name="email" autocomplete="email" required></label>
  <label>電話番号 <input type="tel" name="phone" autocomplete="tel"></label>
  <label>メッセージ <textarea name="message" required></textarea></label>
  <div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
  <label>この欄は空のままにしてください <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
  <!--
任意です。このフォームで Turnstile をオンにしてから、このコメント記号を外し、サイトキーを貼ってください。
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY" data-language="ja"></div>
-->
  <button type="submit">送信</button>
  <p data-status role="status"></p>
</form>
<script>
(function () {
  var form = document.getElementById("fg-ajax");
  if (!form) return;
  var status = form.querySelector("[data-status]");
  form.addEventListener("submit", function (event) {
    event.preventDefault();
    var data = {
      access_key: form.access_key.value,
      _lang: form._lang.value,
      name: form.name.value,
      email: form.email.value,
      phone: form.phone.value,
      message: form.message.value,
      botcheck: form.botcheck.value
    };
    var token = form.querySelector('[name="cf-turnstile-response"]');
    if (token && token.value) data["cf-turnstile-response"] = token.value;
    var body = JSON.stringify(data);
    fetch("https://formgong.com/submit", {
      method: "POST",
      headers: { "Content-Type": "application/json", Accept: "application/json" },
      body: body
    }).then(function (res) { return res.json(); }).then(function (result) {
      if (status) status.textContent = result && result.success ? (result.message || "送信しました。ありがとうございます。") : ((result && result.message) || "送信できませんでした。もう一度お試しください。");
      if (result && result.success) form.reset();
    }).catch(function () {
      if (status) status.textContent = "送信できませんでした。もう一度お試しください。";
    });
  });
})();
</script>
JSON の代わりに FormData を使う同じフォーム
JSON の代わりに FormData を使う同じフォーム
<form id="fg-ajax" action="https://formgong.com/submit" method="POST" style="position:relative">
  <input type="hidden" name="access_key" value="fk_your_access_key">
  <input type="hidden" name="_lang" value="ja">
  <label>お名前 <input type="text" name="name" autocomplete="name" required></label>
  <label>メールアドレス <input type="email" name="email" autocomplete="email" required></label>
  <label>電話番号 <input type="tel" name="phone" autocomplete="tel"></label>
  <label>メッセージ <textarea name="message" required></textarea></label>
  <div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
  <label>この欄は空のままにしてください <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
  <!--
任意です。このフォームで Turnstile をオンにしてから、このコメント記号を外し、サイトキーを貼ってください。
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY" data-language="ja"></div>
-->
  <button type="submit">送信</button>
  <p data-status role="status"></p>
</form>
<script>
(function () {
  var form = document.getElementById("fg-ajax");
  if (!form) return;
  var status = form.querySelector("[data-status]");
  form.addEventListener("submit", function (event) {
    event.preventDefault();
    var body = new FormData(form);
    fetch("https://formgong.com/submit", {
      method: "POST",
      headers: { Accept: "application/json" },
      body: body
    }).then(function (res) { return res.json(); }).then(function (result) {
      if (status) status.textContent = result && result.success ? (result.message || "送信しました。ありがとうございます。") : ((result && result.message) || "送信できませんでした。もう一度お試しください。");
      if (result && result.success) form.reset();
    }).catch(function () {
      if (status) status.textContent = "送信できませんでした。もう一度お試しください。";
    });
  });
})();
</script>

よくある質問

なぜフォームに action の URL が残っているのですか?

JavaScript がオフでも送信が動くようにするためです。スクリプトは、実行されるときだけ preventDefault を呼びます。

JSON と FormData のどちらを送るべきですか?

どちらも有効です。JSON は各フィールドを明示します。FormData は、あとから入力欄を足すときに短く済みます。フォームを読み取るためです。

状態の行が空のままです。何が失敗していますか?

Accept が application/json であること、アクセスキーがご自身のフォームと一致すること、ページがローカルファイルではなく http または https で配信されていることを確認してください。

このフォームでファイルをアップロードできますか?

このスターターではできません。ファイル欄には、添付の有効化と、有効な Turnstile トークンが必要です。その設定はダッシュボードのドキュメントを参照してください。