Nuxt
Un composant Nuxt qui envoie comme un formulaire classique avant l'hydratation, puis avec $fetch, avec l'id du formulaire dans la runtime config. Compatible avec nuxt generate.
Nuxt rend le formulaire côté serveur, donc le HTML qui arrive dans le navigateur est déjà un formulaire fonctionnel. Tant que l'app n'est pas hydratée, il envoie comme n'importe quel formulaire HTML ; ensuite, le composant prend le relais et affiche le résultat sur place. Rien ne tourne sur votre serveur, donc cela fonctionne aussi en site statique généré avec nuxt generate.
Pour envoyer plutôt depuis une route serveur Nuxt avec une clé secrète, voir Vue.
Mise en place
Placez l'id du formulaire dans la runtime config
nuxt.config.ts export default defineNuxtConfig({ runtimeConfig: { public: { ikiformFormId: "frm_xxxxxxxxxxxxxxxx", }, }, });Surchargez-le par environnement avec
NUXT_PUBLIC_IKIFORM_FORM_ID. Avecnuxt generate, la valeur est figée au moment du build : définissez donc la variable dans l'environnement de build.Ajoutez le composant
app/components/ContactForm.vue <script setup lang="ts"> type Result = | { ok: true; id: string } | { ok: false; error: { message: string; fields?: Record<string, string[]> } }; const config = useRuntimeConfig(); const endpoint = `https://ikiform.com/f/${config.public.ikiformFormId}`; const status = ref<"idle" | "sending" | "sent" | "error">("idle"); const errors = ref<Record<string, string[]>>({}); const message = ref(""); async function onSubmit(event: Event) { status.value = "sending"; const result = await $fetch<Result>(endpoint, { method: "POST", headers: { Accept: "application/json" }, body: new FormData(event.currentTarget as HTMLFormElement), ignoreResponseError: true, }).catch(() => null); if (result?.ok) { status.value = "sent"; return; } errors.value = result?.error.fields ?? {}; message.value = result?.error.message ?? "Couldn't reach the server. Try again."; status.value = "error"; } </script> <template> <p v-if="status === 'sent'">Thanks, we got it.</p> <form v-else :action="endpoint" method="post" @submit.prevent="onSubmit"> <label> Email <input name="email" type="email" autocomplete="email" required /> </label> <p v-if="errors.email">{{ errors.email[0] }}</p> <label> Message <textarea name="message" rows="5" /> </label> <input type="hidden" name="_redirect" value="https://example.com/thanks" /> <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden /> <p v-if="status === 'error' && !errors.email" role="alert">{{ message }}</p> <button :disabled="status === 'sending'">{{ status === "sending" ? "Sending" : "Send" }}</button> </form> </template>- Sur Nuxt 3, placez-le dans
components/au lieu deapp/components/. ignoreResponseError: trueempêche$fetchde lever une exception sur les4xx, donc l'enveloppe d'erreur revient sous forme de données. Seules les pannes réseau atteignentcatch.@submit.preventn'existe qu'une fois l'app hydratée. Avant cela, le navigateur envoie versactionet suit_redirect.
- Sur Nuxt 3, placez-le dans
Utilisez-le dans une page
app/pages/contact.vue <template> <ContactForm /> </template>
La solution de repli nécessite le rendu serveur ou le prérendu. Avec ssr: false, la page reste vide tant que JavaScript ne s'exécute pas, donc il n'y a aucun formulaire à envoyer sans lui.
Domaines autorisés
Listez la production ainsi que les hôtes de prévisualisation de votre hébergeur.
| Où tourne le formulaire | À ajouter aux domaines autorisés |
|---|---|
nuxt dev | localhost. Correspond à http://localhost:3000 : Ikiform compare uniquement le nom d'hôte, jamais le port. |
| Votre domaine | example.com, qui couvre aussi www.example.com |
| Vercel | your-project.vercel.app. Les URL de prévisualisation comme your-project-git-branch-team.vercel.app ne correspondent pas ; ajoutez l'hôte de prévisualisation exact le temps de le tester. |
| Netlify | your-site.netlify.app. Les deploy previews (deploy-preview-12--your-site.netlify.app) et les branch deploys (branch--your-site.netlify.app) n'en sont pas des sous-domaines : ajoutez l'hôte de prévisualisation exact le temps de le tester. |
| Cloudflare Pages | your-project.pages.dev. Les URL de prévisualisation comme abc123.your-project.pages.dev en sont des sous-domaines, donc elles correspondent déjà. |
- N'ajoutez jamais
vercel.app,netlify.appoupages.devseul. Tous les sites de cet hébergeur correspondraient, y compris ceux des autres.
Checklist de test
- Lancez
nuxt devaveclocalhostdans les domaines autorisés et envoyez. Le message de remerciement doit remplacer le formulaire. - Désactivez JavaScript dans les outils de développement de votre navigateur, rechargez et envoyez. Vous devez arriver sur la page de remerciement d'Ikiform en local, ou sur
/thankssur votre domainehttps:. - Envoyez un e-mail invalide avec des champs définis et vérifiez que le message apparaît sous le champ.
- Lancez
nuxt generate, déployez le résultat et envoyez depuis l'hôte de prévisualisation.
Dépannage
| Ce que vous voyez | Pourquoi | Solution |
|---|---|---|
FetchError: [POST] "https://ikiform.com/f/...": 422 | ignoreResponseError est absent, donc $fetch lève une exception sur les erreurs | Ajoutez ignoreResponseError: true. |
404 not_found, et l'action se termine par /f/undefined | L'id du formulaire n'était pas défini au moment du build | Définissez NUXT_PUBLIC_IKIFORM_FORM_ID dans l'environnement de build, ou la valeur par défaut dans nuxt.config.ts. |
| Sans JavaScript, rien ne se passe | La page est rendue côté client avec ssr: false | Activez le rendu serveur ou prérendez la page. |
Les soumissions arrivent dans le filtre spam avec origin_mismatch | La page qui a envoyé ne fait pas partie des domaines autorisés du formulaire | Ajoutez l'hôte du tableau ci-dessus. Avec Reject, les mêmes envois reçoivent plutôt 403 origin_not_allowed. |