Construye formularios HTML en páginas de Astro
En modo SSR, las páginas Astro pueden mostrar y manejar formularios. En esta receta, usarás un formulario HTML estándar para enviar datos al servidor. El script de tu frontmatter manejará los datos en el servidor, sin enviar JavaScript al cliente.
Prerrequisitos
- Un proyecto con SSR (
output: 'server'
) habilitado
Receta
-
Crea o identifica una página
.astro
que contenga tu formulario y tu código de manejo. Por ejemplo, podrías agregar una página de registro:src/pages/register.astro ------<h1>Register</h1> -
Agrega una etiqueta
<form>
con algunas entradas a la página. Cada entrada debe tener un atributoname
que describa el valor de esa entrada.Asegúrate de incluir un elemento
<button>
o<input type="submit">
para enviar el formulario.src/pages/register.astro ------<h1>Registro</h1><form><label>Usuario:<input type="text" name="username" /></label><label>Correo electrónico:<input type="email" name="email" /></label><label>Contraseña:<input type="password" name="password" /></label><button>Enviar</button></form> -
Usa atributos de validación para proveer validación básica del lado del cliente que funciona incluso si JavaScript está deshabilitado.
En este ejemplo,
required
previene el envío del formulario hasta que el campo esté lleno.minlength
establece una longitud mínima requerida para el texto de entrada.type="email"
también introduce validación que solo aceptará un formato de correo electrónico válido.
src/pages/register.astro ------<h1>Registro</h1><form><label>Usuario:<input type="text" name="username" required /></label><label>Correo electrónico:<input type="email" name="email" required /></label><label>Contraseña:<input type="password" name="password" required minlength="6" /></label><button>Enviar</button></form>Puedes agregar lógica de validación personalizada que se refiera a múltiples campos usando una etiqueta
<script>
y la API de validación de restricciones.Para escribir validación de lógica compleja más fácilmente, puedes construir tu formulario usando un framework de frontend y elegir una librería de formularios como React Hook Form o Felte.
-
El envío del formulario causará que el navegador solicite la página nuevamente. Cambia el método de transferencia de datos del formulario a
POST
para enviar los datos del formulario como parte del cuerpo de laRequest
, en lugar de como parámetros de URL.src/pages/register.astro ------<h1>Registro</h1><form method="POST"><label>Usuario:<input type="text" name="username" required /></label><label>Correo electrónico:<input type="email" name="email" required /></label><label>Contraseña:<input type="password" name="password" required minlength="6" /></label><button>Enviar</button></form> -
Comprueba el método
POST
en el frontmatter y accede a los datos del formulario usandoAstro.request.formData()
. Envuelve esto en un bloquetry ... catch
para manejar los casos en los que la solicitudPOST
no fue enviada por un formulario y elformData
es inválido.src/pages/register.astro ---if (Astro.request.method === "POST") {try {const data = await Astro.request.formData();const name = data.get("username");const email = data.get("email");const password = data.get("password");// Do something with the data} catch (error) {if (error instanceof Error) {console.error(error.message);}}}---<h1>Registro</h1><form method="POST"><label>Usuario:<input type="text" name="username" required /></label><label>Correo electrónico:<input type="email" name="email" required /></label><label>Contraseña:<input type="password" name="password" required minlength="6" /></label><button>Enviar</button></form> -
Valida los datos del formulario en el servidor. Esto debería incluir la misma validación realizada en el cliente para evitar envíos maliciosos a tu endpoint y brindar soporte a los raros navegadores heredados que no tienen validación de formularios.
También puedes incluir validación que no se puede hacer en el cliente. Por ejemplo, este ejemplo verifica si el correo electrónico ya está en la base de datos.
Los mensajes de error pueden ser enviados al cliente almacenándolos en un objeto
errors
y accediendo a él en la plantilla.src/pages/register.astro ---import { isRegistered, registerUser } from "../../data/users"import { isValidEmail } from "../../utils/isValidEmail";const errors = { username: "", email: "", password: "" };if (Astro.request.method === "POST") {try {const data = await Astro.request.formData();const name = data.get("username");const email = data.get("email");const password = data.get("password");if (typeof name !== "string" || name.length < 1) {errors.username += "Please enter a username. ";}if (typeof email !== "string" || !isValidEmail(email)) {errors.email += "Email is not valid. ";} else if (await isRegistered(email)) {errors.email += "Email is already registered. ";}if (typeof password !== "string" || password.length < 6) {errors.password += "Password must be at least 6 characters. ";}const hasErrors = Object.values(errors).some(msg => msg)if (!hasErrors) {await registerUser({name, email, password});return Astro.redirect("/login");}} catch (error) {if (error instanceof Error) {console.error(error.message);}}}---<h1>Registro</h1><form method="POST"><label>Usuario:<input type="text" name="username" /></label>{errors.username && <p>{errors.username}</p>}<label>Correo electrónico:<input type="email" name="email" required /></label>{errors.email && <p>{errors.email}</p>}<label>Contraseña:<input type="password" name="password" required minlength="6" /></label>{errors.password && <p>{errors.password}</p>}<button>Registro</button></form>