Formulaire de contact AJAX
Les mêmes champs de contact, envoyés en JSON avec fetch. Le visiteur reste sur la page et voit un court statut.
Ce que vous copiez
Ce modèle envoie les mêmes champs de contact avec fetch, afin que le visiteur reste sur votre page et lise un court statut.
Le formulaire a toujours une action et la méthode POST. Si JavaScript ne s’exécute pas, le navigateur fait un envoi ordinaire.
Ce repli compte pour les navigateurs plus anciens et pour les personnes qui bloquent les scripts. Vous ne tenez pas deux formulaires.
L’extrait principal envoie du JSON. Il règle Content-Type sur application/json et Accept sur application/json.
Le succès est le booléen success dans le JSON. Lorsqu’il vaut true, l’extrait montre le message de la réponse, ou un court remerciement, et vide le formulaire.
Lorsqu’il vaut false, l’extrait montre le message de la réponse. Formgong écrit ce message dans la langue de _lang.
JSON et FormData
Un corps JSON doit lister les champs que vous voulez envoyer. L’extrait comprend access_key, _lang, name, email, phone, message et botcheck.
Si vous décommentez Turnstile plus tard, le chemin JSON copie aussi cf-turnstile-response lorsque ce champ a une valeur.
L’extrait supplémentaire utilise FormData au lieu de JSON. Le navigateur fixe le type de contenu, y compris la boundary. Ne définissez pas Content-Type vous-même.
FormData reprend chaque champ du formulaire, y compris un jeton Turnstile si le widget est dans le formulaire.
Les deux chemins envoient Accept: application/json. Sans cet en-tête, un envoi de formulaire ordinaire du navigateur reçoit la page de remerciement, pas du JSON.
N’envoyez pas à la fois un corps JSON et un corps multipart. Choisissez-en un. Les deux extraits sont des alternatives, pas des couches.
Spam, Telegram et limites
Gardez le honeypot nommé botcheck, vide, hors de l’écran, avec tabindex -1. Un honeypot rempli est stocké comme spam et n’est pas livré.
Les noms de champs restent courts pour que Telegram puisse les imprimer en gras. Ne renommez pas email en une longue phrase.
La clé d’accès reste dans la page. La déplacer vers un secret de serveur ne rend pas le formulaire plus sûr, et cet extrait n’a pas de serveur.
Sur la formule gratuite, Telegram est immédiat et l’e-mail est un résumé quotidien. La boîte de réception conserve les soumissions pendant 30 jours.
La formule gratuite comprend 300 soumissions par mois. Une soumission de spam n’en consomme pas une.
Cet aperçu n’envoie rien. Branchez l’extrait sur votre site, puis envoyez un test depuis cette page.
Formgong fait tourner le service. Pour de l’aide sur le produit, écrivez à support@formgong.com.
Aperçu
Code du formulaire
<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="fr">
<label>Nom <input type="text" name="name" autocomplete="name" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" required></label>
<label>Téléphone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Message <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>Laissez ce champ vide <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<!--
Facultatif. Activez Turnstile pour ce formulaire, retirez ces marques de commentaire et collez la clé du site.
<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="fr"></div>
-->
<button type="submit">Envoyer</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 || "Envoyé. Merci !") : ((result && result.message) || "Échec de l’envoi. Veuillez réessayer.");
if (result && result.success) form.reset();
}).catch(function () {
if (status) status.textContent = "Échec de l’envoi. Veuillez réessayer.";
});
});
})();
</script>Le même formulaire avec FormData au lieu de JSON
<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="fr">
<label>Nom <input type="text" name="name" autocomplete="name" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" required></label>
<label>Téléphone <input type="tel" name="phone" autocomplete="tel"></label>
<label>Message <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>Laissez ce champ vide <input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<!--
Facultatif. Activez Turnstile pour ce formulaire, retirez ces marques de commentaire et collez la clé du site.
<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="fr"></div>
-->
<button type="submit">Envoyer</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 || "Envoyé. Merci !") : ((result && result.message) || "Échec de l’envoi. Veuillez réessayer.");
if (result && result.success) form.reset();
}).catch(function () {
if (status) status.textContent = "Échec de l’envoi. Veuillez réessayer.";
});
});
})();
</script>Questions et réponses
Pourquoi le formulaire a-t-il encore une URL d’action ?
Pour que l’envoi fonctionne encore lorsque JavaScript est désactivé. Le script n’appelle preventDefault que lorsqu’il s’exécute.
Dois-je envoyer du JSON ou du FormData ?
Les deux sont valables. JSON nomme chaque champ explicitement. FormData est plus court lorsque vous ajoutez des inputs plus tard, parce qu’il lit le formulaire.
La ligne de statut reste vide. Qu’est-ce qui a échoué ?
Vérifiez qu’Accept vaut application/json, que la clé d’accès correspond à un formulaire qui vous appartient, et que la page est servie en http ou https, pas comme un fichier local.
Ce formulaire peut-il envoyer un fichier ?
Pas dans ce modèle. Les champs de fichier exigent les pièces jointes activées et un jeton Turnstile valide. Utilisez la documentation du tableau de bord pour cette mise en place.