Cree un formulario de contacto en Next.js
Un formulario de contacto de Next.js puede publicarse desde un componente de cliente directamente en un punto final de LittleReply publicado. Mantenga la clave pública en el navegador, mantenga las credenciales de administración solo en el servidor y muestre el resultado del envío almacenado por separado de la entrega del correo electrónico.
Crear un formulario gratisUn ejemplo copiable
'use client';
import { useState, useRef } from 'react';
export default function Contact() {
const [etat, setEtat] = useState('');
const [busy, setBusy] = useState(false);
const tentative = useRef({ contenu: '', id: '' });
async function envoyer(event) {
event.preventDefault();
const form = event.currentTarget;
if (!form.reportValidity()) return;
const data = new FormData(form);
const fields = { name: data.get('name'), email: data.get('email'), message: data.get('message') };
const contenu = JSON.stringify(fields);
if (contenu !== tentative.current.contenu) tentative.current = { contenu, id: crypto.randomUUID() };
setBusy(true); setEtat("Enviando…");
try {
const response = await fetch("https://littlereply.com/api/submit", {
method: 'POST', headers: { 'Content-Type': 'application/json', 'Idempotency-Key': tentative.current.id },
body: JSON.stringify({ form_key: "YOUR_ACCESS_KEY", fields })
});
const result = await response.json();
if (!response.ok) throw new Error(response.status === 429 ? "Límite alcanzado. Vuelve a intentarlo más tarde." : "No se pudo enviar. Verifique los campos e inténtelo nuevamente.");
setEtat("Tu mensaje fue guardado. La entrega de correo electrónico se rastrea por separado.");
} catch (error) { setEtat(error instanceof Error ? error.message : "No se pudo enviar."); }
finally { setBusy(false); }
}
return <form onSubmit={envoyer}>
<label>Tu nombre<input name='name' autoComplete='name' required /></label>
<label>Tu correo electrónico<input name='email' type='email' autoComplete='email' required /></label>
<label>tu mensaje<textarea name='message' required maxLength={5000} /></label>
<button disabled={busy}>enviar mensaje</button>
<p role='status' aria-live='polite'>{etat}</p>
</form>;
}la clave YOUR_ACCESS_KEY es un marcador de posición para reemplazar con la clave pública de su formulario. El código no contiene clave de servidor ni dirección de destino.
Elija el límite más pequeño
Enviar directamente cuando el navegador solo envía campos de formulario públicos. Agregue su propio controlador de ruta solo cuando necesite un enriquecimiento del servidor confiable o una integración privada que no se pueda ejecutar en el navegador.
No coloque un token de administración en una variable NEXT_PUBLIC. La clave del formulario público está diseñada para la admisión; Las credenciales de cuenta y API no lo son.
Estados de éxito, error y pendiente del modelo
Deshabilite los clics repetidos mientras la solicitud esté pendiente, mantenga las entradas después de errores recuperables y use una clave de idempotencia para reintentos de contenido sin cambios.
Una respuesta 202 confirma una ingesta duradera. Presente ese estado con precisión y utilice el registro de entrega del espacio de trabajo para obtener resultados de correo electrónico o webhook.
Verificar el host implementado
Pruebe los hosts de producción y vista previa de Vercel reales con la política de origen permitido. Verifique los errores del navegador, la respuesta de la red, el envío almacenado y el historial de notificaciones.
Pruebe la plantilla antes de crear una cuenta.
Vista previa local: los cambios permanecen en este navegador. No se envía ningún mensaje o correo electrónico.
contacto HTML
Nombre, correo electrónico y mensaje: lo esencial para iniciar una conversación.
LittleReply<!doctype html>
<html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Formulario de contacto</title>
<style>form[data-littlereply]{max-width:640px;margin:2rem auto;padding:1.5rem;font:16px/1.6 system-ui,sans-serif;color:#202033;background:white;border:1px solid #e4e4ee;border-radius:16px;box-sizing:border-box}form[data-littlereply] label{display:block;margin-top:1rem;font-weight:600}form[data-littlereply] input,form[data-littlereply] textarea,form[data-littlereply] select{box-sizing:border-box;width:100%;padding:.75rem;font:inherit;border:1px solid #727285;border-radius:8px;background:white;color:#202033}form[data-littlereply] input[type=checkbox],form[data-littlereply] input[type=radio]{width:auto}form[data-littlereply] button{margin-top:1rem;padding:.8rem 1.1rem;font:inherit;font-weight:600;border:0;border-radius:8px;background:var(--form-accent,#4f46e5);color:white;cursor:pointer}form[data-littlereply] :focus-visible{outline:3px solid #f59e0b;outline-offset:3px}form[data-littlereply] button:disabled{opacity:.6}form[data-littlereply] [role=status]{min-height:1.6em}form[data-littlereply] fieldset{border:0;padding:0}form[data-littlereply] .privacy-notice{font-size:.875rem;color:#4b4b60}
form[data-littlereply]{--form-accent:#4f46e5;--form-ink:#ffffff}
form[data-littlereply] button{color:var(--form-ink)}form[data-littlereply] button[data-fq-back]{background:#eee;color:#202033}form[data-littlereply] [hidden]{display:none}</style></head><body>
<form action="https://littlereply.com/api/submit" method="POST" data-littlereply="YOUR_ACCESS_KEY" data-locale="es" data-success="Su mensaje ha sido almacenado. Responderemos pronto.">
<input type="hidden" name="_fq_key" value="YOUR_ACCESS_KEY" />
<input type="text" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" aria-hidden="true" />
<label for="fq_name">Tu nombre *</label>
<input type="text" name="name" id="fq_name" required autocomplete="name" />
<label for="fq_email">Su dirección de correo electrónico *</label>
<input type="email" name="email" id="fq_email" required autocomplete="email" />
<label for="fq_message">tu mensaje *</label>
<textarea name="message" id="fq_message" required maxlength="5000" rows="5"></textarea>
<button type="submit">enviar mi mensaje</button>
<p role="status" aria-live="polite"></p>
</form>
<!-- Errores AJAX accesibles y reintentos sin duplicados -->
<script src="https://littlereply.com/client/v1.js" data-api="https://littlereply.com" defer></script>
</body></html>Reemplace YOUR_ACCESS_KEY con la clave pública de su formulario. El código incluye sus estilos y una mejora AJAX; el HTML POST nativo también funciona sin JavaScript.
Fuentes
Preguntas frecuentes
¿Necesito una acción del servidor?
No. El envío directo al navegador es suficiente para los campos públicos. Utilice un límite de servidor solo para trabajos confiables.
¿La clave del formulario es secreta?
No. Puede estar presente en el código del cliente y solo autoriza el ingreso público.