Cómo crear un formulario de contacto en Astro
Astro es uno de los mejores frameworks para crear sitios rápidos centrados en contenido. Como Astro genera HTML estático por defecto, añadir un formulario de contacto requiere apuntar el formulario a un servicio backend externo en lugar de procesar los envíos en el servidor.
Esta guía explica cómo crear un formulario de contacto listo para producción en Astro, desde el marcado básico hasta el envío AJAX con protección antispam.
Formulario de contacto Astro básico
Create a new page at src/pages/contact.astro:
------
<html lang="en"> <head> <title>Contact Us</title> </head> <body> <form action="https://api.formsfort.com/submit" method="POST"> <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<label for="name">Name</label> <input type="text" id="name" name="name" autocomplete="name" required />
<label for="email">Email</label> <input type="email" id="email" name="email" autocomplete="email" required />
<label for="message">Message</label> <textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send message</button> </form> </body></html>Esto funciona inmediatamente. Astro genera el HTML tal cual y el navegador maneja el envío del formulario al endpoint externo.
Agregar protección antispam
Campo Honeypot
Agregue un campo oculto dentro del formulario para detectar bots básicos:
<input type="text" name="botcheck" style="position: absolute; left: -9999px; opacity: 0;" tabindex="-1" autocomplete="off"/>Cloudflare Turnstile
Agregar Turnstile para una mayor protección contra bots:
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITE_KEY"></div><script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>Coloque el widget Turnstile antes del botón de enviar. El token de respuesta se incluye automáticamente en el envío del formulario.
Agregar validación
Utilice atributos de validación HTML5 para la validación del lado del cliente:
<label for="name">Name</label><input type="text" id="name" name="name" autocomplete="name" minlength="2" maxlength="100" required/>
<label for="email">Email</label><input type="email" id="email" name="email" autocomplete="email" required />
<label for="message">Message</label><textarea id="message" name="message" rows="5" minlength="10" maxlength="5000" required></textarea>Envío AJAX en Astro
Para una experiencia más fluida sin recargas de páginas, agregue un script del lado del cliente:
------
<form id="contactForm" action="https://api.formsfort.com/submit" method="POST"> <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" /> <input type="hidden" name="botcheck" style="position:absolute;left:-9999px;opacity:0" tabindex="-1" autocomplete="off" />
<label for="name">Name</label> <input type="text" id="name" name="name" required />
<label for="email">Email</label> <input type="email" id="email" name="email" required />
<label for="message">Message</label> <textarea id="message" name="message" rows="5" required></textarea>
<button type="submit" id="submitBtn">Send message</button> <p id="formStatus" aria-live="polite"></p></form>
<script> const form = document.getElementById("contactForm"); const status = document.getElementById("formStatus"); const btn = document.getElementById("submitBtn");
form.addEventListener("submit", async (e) => { e.preventDefault(); btn.disabled = true; btn.textContent = "Sending..."; status.textContent = "";
try { const response = await fetch(form.action, { method: "POST", body: new FormData(form), });
if (response.ok) { status.textContent = "Message sent successfully. We will be in touch."; form.reset(); } else { const data = await response.json().catch(() => null); status.textContent = data?.message ?? "Something went wrong. Please try again."; } } catch { status.textContent = "Network error. Please check your connection and try again."; } finally { btn.disabled = false; btn.textContent = "Send message"; } });</script>The script intercepts the form submission, sends it via fetch(), and updates the UI with the result. The aria-live="polite" attribute ensures screen readers announce status changes.
Usar variables de entorno Astro para la clave de acceso
Almacene la clave de acceso en una variable de entorno en lugar de codificarla:
---const accessKey = import.meta.env.PUBLIC_FORMSFORT_ACCESS_KEY;---
<form action="https://api.formsfort.com/submit" method="POST"> <input type="hidden" name="access_key" value="{accessKey}" /> <!-- rest of form --></form>Create a .env file:
PUBLIC_FORMSFORT_ACCESS_KEY=ff_your_key_hereOnly variables prefixed with PUBLIC_ are exposed to the client bundle in Astro.
Formulario de contacto con islas Astro (React, Vue, Svelte)
Si prefiere usar un componente de framework para el formulario, cree una isla:
import { useState } from "react";
export default function ContactForm({ accessKey }: { accessKey: string }) { const [status, setStatus] = useState("");
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault(); setStatus("Sending...");
const response = await fetch("https://api.formsfort.com/submit", { method: "POST", body: new FormData(e.currentTarget), });
setStatus(response.ok ? "Message sent." : "Something went wrong."); }
return ( <form onSubmit={handleSubmit}> <input type="hidden" name="access_key" value={accessKey} /> <input type="email" name="email" required placeholder="Email" /> <textarea name="message" required placeholder="Message" /> <button type="submit">Send</button> <p>{status}</p> </form> );}Úselo en su página Astro con una directiva de cliente:
---import ContactForm from "../components/ContactForm";const accessKey = import.meta.env.PUBLIC_FORMSFORT_ACCESS_KEY;---
<ContactForm client:load {accessKey} />Redirigir después del envío
Para envíos estándar (no AJAX), redirija a una página de agradecimiento:
<input type="hidden" name="_redirect" value="https://yoursite.com/thanks" />Create the thank-you page at src/pages/thanks.astro.
Resumen
Los formularios de contacto en Astro funcionan apuntando formularios HTML estándar a un endpoint de backend de formularioss alojado. No hacen falta adaptadores de servidor, rutas API ni funciones serverless. Añada protección antispam con campos honeypot y CAPTCHA, valide con atributos HTML5 y, si lo necesita, gestione el envío con AJAX para una experiencia más fluida. El resultado es un formulario de contacto rápido, listo para producción y compatible con la build estático de Astro.
Preguntas frecuentes
¿Astro admite el envío de formularios?
Astro genera HTML estático por defecto, así que los formularios necesitan un backend externo para recibir envíos. Apunte el action del formulario a un endpoint de formulario alojado como FormsFort, y Astro tratará todo lo demás como HTML estándar.
¿Necesito adaptadores de servidor Astro para formularios?
No. Con un backend de formularios alojado, no necesita @astrojs/node, @astrojs/vercel ni ningún adaptador de servidor. El formulario se envía directamente en el endpoint externo desde el navegador.
¿Puedo usar colecciones de contenido de Astro con formularios?
Las colecciones de contenido son para administrar archivos de datos y rebajas, no para procesar envíos de formularios. Utilice un servicio de backend de formularios para el manejo de envíos.
¿Cómo agrego un formulario de contacto a una isla Astro?
Utilice un componente de framework (React, Vue, Svelte) con la directiva client:load o client:visible. El componente maneja el envío del formulario a través de fetch() al endpoint del backend de formularios.
¿Cuál es la mejor protección antispam para los formularios Astro?
Combina un campo de honeypot, restricción de dominio y CAPTCHA de Cloudflare Turnstile. Los tres funcionan con formularios HTML estándar en Astro sin ningún código del lado del servidor.
Comience gratis
¿Listo para agregar formularios a su sitio estático?
No se requiere backend. Apunte su formulario HTML a FormsFort y comience a recibir envíos en minutos.