Nuxt
Un componente de Nuxt que envía como un formulario normal antes de la hidratación y con $fetch después, con el id del formulario en la runtime config. Funciona con nuxt generate.
Nuxt renderiza el formulario en el servidor, así que el HTML que llega al navegador ya es un formulario que funciona. Hasta que la app se hidrata, envía como cualquier formulario HTML; después, el componente toma el control y muestra el resultado en su sitio. No se ejecuta nada en tu servidor, así que también funciona como sitio estático generado con nuxt generate.
Para enviar desde una ruta de servidor de Nuxt con una clave secreta, consulta Vue.
Configúralo
Pon el id del formulario en la runtime config
nuxt.config.ts export default defineNuxtConfig({ runtimeConfig: { public: { ikiformFormId: "frm_xxxxxxxxxxxxxxxx", }, }, });Sobrescríbelo por entorno con
NUXT_PUBLIC_IKIFORM_FORM_ID. Connuxt generate, el valor se fija en tiempo de build, así que define la variable en el entorno de build.Añade el componente
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>- En Nuxt 3, ponlo en
components/en lugar deapp/components/. ignoreResponseError: trueevita que$fetchlance una excepción ante un4xx, así que el formato de error vuelve como datos. Solo los fallos de red llegan alcatch.@submit.preventsolo existe cuando la app ya se hidrató. Antes de eso, el navegador envía aactiony sigue_redirect.
- En Nuxt 3, ponlo en
Úsalo en una página
app/pages/contact.vue <template> <ContactForm /> </template>
La alternativa necesita renderizado en servidor o prerenderizado. Con ssr: false, la página está vacía hasta que se ejecuta JavaScript, así que sin él no hay formulario que enviar.
Dominios permitidos
Incluye producción y los hosts de vista previa de donde despliegues.
| Dónde funciona el formulario | Añadir a Allowed domains |
|---|---|
nuxt dev | localhost. Coincide con http://localhost:3000: Ikiform solo compara el nombre de host, nunca el puerto. |
| Tu dominio | example.com, que también cubre www.example.com |
| Vercel | your-project.vercel.app. Las URL de vista previa como your-project-git-branch-team.vercel.app no coinciden con él; añade el host exacto de la vista previa mientras la pruebas. |
| Netlify | your-site.netlify.app. Los deploy previews (deploy-preview-12--your-site.netlify.app) y los branch deploys (branch--your-site.netlify.app) no son subdominios suyos, así que añade el host exacto de la vista previa mientras la pruebas. |
| Cloudflare Pages | your-project.pages.dev. Las URL de vista previa como abc123.your-project.pages.dev son subdominios suyos, así que ya coinciden. |
- Nunca añadas
vercel.app,netlify.appnipages.devsolos. Coincidiría cualquier sitio de ese host, incluidos los de otras personas.
Lista de pruebas
- Ejecuta
nuxt devconlocalhosten los dominios permitidos y envía. El mensaje de agradecimiento debería sustituir al formulario. - Desactiva JavaScript en las herramientas de desarrollo del navegador, recarga y envía. Deberías llegar a la página de agradecimiento de Ikiform en local, o a
/thanksen tu dominiohttps:. - Envía un email no válido con campos definidos y confirma que el mensaje aparece debajo del campo.
- Ejecuta
nuxt generate, despliega el resultado y envía desde el host de vista previa.
Solución de problemas
| Qué ves | Por qué | Solución |
|---|---|---|
FetchError: [POST] "https://ikiform.com/f/...": 422 | Falta ignoreResponseError, así que $fetch lanza excepciones ante errores | Añade ignoreResponseError: true. |
404 not_found, y el action termina en /f/undefined | El id del formulario no estaba definido cuando se generó el sitio | Define NUXT_PUBLIC_IKIFORM_FORM_ID en el entorno de build, o el valor por defecto en nuxt.config.ts. |
| Sin JavaScript no pasa nada | La página se renderiza en el cliente con ssr: false | Activa el renderizado en servidor o prerenderiza la página. |
Los envíos llegan al filtro de spam con origin_mismatch | La página que envió no está entre los dominios permitidos del formulario | Añade el host de la tabla de arriba. Si eliges Reject, esos mismos envíos reciben 403 origin_not_allowed. |