Enviar formularios con JavaScript (AJAX)
Disponible en todos los planes
Puedes utilizar @formspree/ajax para enviar tus formularios de Formspree con JavaScript puro, sin escribir tu propia lógica de envío con fetch, Axios o jQuery.
La biblioteca funciona con formularios HTML estándar y añade un manejo declarativo de formularios mediante atributos de datos o una pequeña API de JavaScript. Gestiona el envío del formulario, el estado de carga, los errores de validación y los mensajes de éxito de forma automática.
Cómo funciona
@formspree/ajax te ofrece una forma declarativa de conectar un formulario. En lugar de escuchar manualmente los eventos de envío y escribir tu propio manejo de solicitudes, marcas tu formulario con atributos de datos y lo inicializas con tu ID de formulario de Formspree.
De forma predeterminada, la biblioteca gestiona:
- el envío del formulario
- el estado de carga en el botón de envío
- los errores de validación a nivel de campo
- los errores a nivel de formulario
- los mensajes de éxito
- el estado de campo inválido con
aria-invalid="true"
Así es como puedes implementarlo en tu proyecto:
Paso 1: Configurar @formspree-ajax en tu proyecto
Puedes usar @formspree/ajax de dos maneras, según tu configuración:
- Con un bundler (ESM mediante npm/yarn)
- Sin un bundler (etiqueta script/CDN)
Opción 1: Usando un bundler (ESM)
Instala la biblioteca:
npm install @formspree/ajax # via npm, or
yarn add @formspree/ajax # via yarn
E inicializa tu formulario en JavaScript:
import { initForm } from '@formspree/ajax';
initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
});
Asegúrate de que el ID de tu elemento de formulario HTML coincida con el ID que pasas a la propiedad formElement. Y reemplaza YOUR_FORM_ID con el ID del formulario que recibes en el panel de Formspree.
Opción 2: Usando una etiqueta script (sin paso de compilación)
Si no estás usando un bundler, añade este fragmento antes de la etiqueta de cierre </body>:
<script>
window.formspree =
window.formspree ||
function () {
(formspree.q = formspree.q || []).push(arguments);
};
formspree(
'initForm',
{ formElement: '#contact-form', formId: 'YOUR_FORM_ID' }
);
</script>
<script src="https://unpkg.com/@formspree/ajax@1" defer></script>
Al igual que con la primera opción, asegúrate de que el ID de tu elemento de formulario HTML coincida con el ID que pasas a la propiedad formElement. Y reemplaza YOUR_FORM_ID con el ID del formulario que recibes en el panel de Formspree.
Paso 2: Crear tu formulario
Una vez que hayas configurado @formspree/ajax en tu proyecto, así es como puedes crear un formulario con él:
<div data-fs-success></div>
<div data-fs-error></div>
<form id="contact-form">
<label for="email">Email</label>
<input type="email" id="email" name="email" data-fs-field />
<span data-fs-error="email"></span>
<button type="submit" data-fs-submit-btn>Send</button>
</form>
Una vez más, asegúrate de que el valor del atributo
idde tu formulario coincida con el ID que pasaste comoformIden la llamada ainitFormdel paso anterior.
La biblioteca enviará automáticamente el formulario a Formspree, deshabilitará el botón de envío mientras la solicitud está en curso, mostrará los errores de validación y mostrará un mensaje de éxito.
Atributos de datos
La biblioteca @formspree-ajax incluye algunos atributos que te permiten controlar cómo se comporta el formulario sin requerir JavaScript adicional.
data-fs-error="fieldName"
Úsalo en un <span> o <div> para mostrar errores de validación a nivel de campo.
<span data-fs-error="email"></span>
Si el elemento está vacío, Formspree inyecta el mensaje de error de la API. Si el elemento ya contiene contenido, ese contenido se muestra u oculta en su lugar.
data-fs-error
Úsalo sin un valor para mostrar errores a nivel de formulario.
<div data-fs-error></div>
Esto es útil para errores generales de envío que no pertenecen a un campo específico.
data-fs-success
Úsalo para mostrar un mensaje de éxito después del envío.
<div data-fs-success></div>
Si el elemento está vacío, se muestra el mensaje predeterminado. Si ya tiene contenido, se utiliza ese contenido en su lugar.
data-fs-field
Úsalo en los campos del formulario que deban recibir aria-invalid="true" cuando la validación falle.
<input type="email" name="email" data-fs-field />
La biblioteca lee el nombre del campo desde el atributo name del elemento.
data-fs-submit-btn
Úsalo en el botón de envío para que se deshabilite durante el envío y se vuelva a habilitar después.
<button type="submit" data-fs-submit-btn>Send</button>
Comportamiento predeterminado
Si no anulas nada, la biblioteca proporciona valores predeterminados sensatos:
- El botón de envío se deshabilita mientras se envía el formulario.
- Los errores de campo se muestran dentro de los elementos
data-fs-error="fieldName"correspondientes. - Los campos inválidos reciben
aria-invalid="true". - Se muestra un mensaje de éxito en el elemento
data-fs-success. - Se muestra un mensaje de error a nivel de formulario en el elemento
data-fs-error. - Si no hay un elemento
data-fs-successni un manejadoronSuccesspersonalizado, el formulario se reemplaza con un mensaje “Thank you!”. - Si hay un elemento
data-fs-successy no hay un manejadoronSuccesspersonalizado, el formulario se reinicia tras un envío exitoso. - Se inyectan estilos predeterminados básicos automáticamente.
Configuración avanzada
La biblioteca también ofrece formas de personalizar aún más el comportamiento y la apariencia de tu formulario.
Añadir datos adicionales a cada envío
Puedes usar la opción data para agregar valores adicionales a cada envío de formulario. Los valores pueden ser:
- cadenas estáticas
- funciones síncronas
- funciones asíncronas
Cualquier valor undefined se omite. Así es como se usa:
initForm({
formElement: '#my-form',
formId: 'YOUR_FORM_ID',
// This data will be added to every submission
data: {
source: 'landing-page',
referrer: () => document.referrer || undefined,
sessionId: async () => await fetchSessionId(),
},
});
Es útil para adjuntar metadatos como nombres de campañas, fuentes de referencia o IDs de sesión sin tener que añadir inputs ocultos a tu HTML.
Callbacks del ciclo de vida
Puedes engancharte a las distintas etapas del ciclo de vida del envío.
initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
// Called when the form is initialized
onInit: (context) => {
console.log('Form initialized');
},
// Called before submission is sent.
onSubmit: (context) => {
console.log('Submitting form');
},
// Called on successful submission.
onSuccess: (context, result) => {
console.log('Submission succeeded', result);
},
// Called if validation errors are received from Formspree
onError: (context, error) => {
console.log('Validation error', error);
},
// Called if unexpected errors are received (e.g., network failure).
onFailure: (context, error) => {
console.log('Unexpected error', error);
},
});
El objeto context contiene el formulario actual (HTMLFormElement), los detalles del endpoint, el cliente y el objeto de configuración que pasaste a initForm.
Estos callbacks se pueden usar para:
- Seguimiento de eventos (analítica, conversiones, abandonos)
- Mostrar UI personalizada (spinners, toasts, banners)
- Redirigir tras un envío exitoso
- Registrar o depurar solicitudes y fallos
- Manejo personalizado de errores de validación o a nivel de formulario
- Ejecutar efectos secundarios antes o después del envío (por ejemplo, guardar estado, activar workflows)
Renderizado personalizado
Puedes anular el comportamiento predeterminado de la UI proporcionando métodos de renderizado personalizados en initForm(). Esto es útil si quieres tener control total sobre cómo aparecen los estados de carga, los errores y los mensajes de éxito.
initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
enable: (context) => {},
disable: (context) => {},
renderFieldErrors: (context, error) => {},
renderSuccess: (context, message) => {},
renderFormError: (context, message) => {},
});
Métodos disponibles
| Método | Cuándo se ejecuta | Usos comunes |
|---|---|---|
disable(context) | Cuando comienza el envío | Añadir estado de carga, deshabilitar botones/inputs |
enable(context) | Después de que el envío se completa | Eliminar spinners, volver a habilitar la UI |
renderFieldErrors(context, error) | En errores de validación | UI de error personalizada, errores agrupados, mensajes toast |
renderSuccess(context, message) | En envíos exitosos | Reemplazar el formulario, mostrar toast, redirigir |
renderFormError(context, message) | En errores a nivel de formulario | Banners de error, alertas, mensajería centralizada |
Así es como se usan:
initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
disable: ({ form }) => form.classList.add('loading'),
enable: ({ form }) => form.classList.remove('loading'),
renderSuccess: ({ form }, message) => {
form.innerHTML = `<p>${message}</p>`;
},
});
Estilos
La biblioteca incluye estilos predeterminados para errores, campos inválidos y mensajes de éxito. Puedes anularlos con tu propio CSS.
[data-fs-error] {
color: #dc3455;
}
[data-fs-field][aria-invalid='true'] {
border-color: #dc3455;
}
[data-fs-success][data-fs-active] {
background: #de4dda;
}
[data-fs-error=''][data-fs-active] {
background: #f87dda;
color: #72c124;
}
Limpieza
initForm() devuelve un handle con un método destroy(). Puedes usarlo si necesitas limpiar el comportamiento del formulario más adelante.
const handle = initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
});
// Clean up when needed
handle.destroy();
Ejemplo completo en ESM
Aquí tienes un ejemplo completo usando un formulario HTML simple y @formspree/ajax con un bundler. Primero, inicializa el formulario con tu ID de formulario de Formspree:
import { initForm } from '@formspree/ajax';
initForm({
formElement: '#contact-form',
formId: 'YOUR_FORM_ID',
});
Luego, crea el formulario HTML con los atributos de datos descritos arriba:
<div data-fs-success></div>
<div data-fs-error></div>
<form id="contact-form">
<label for="email">Email</label>
<input type="email" id="email" name="email" data-fs-field />
<span data-fs-error="email"></span>
<label for="message">Message</label>
<textarea id="message" name="message" data-fs-field></textarea>
<span data-fs-error="message"></span>
<button type="submit" data-fs-submit-btn>Send</button>
</form>
Ejemplo con etiqueta script
Si quieres usar la biblioteca sin un paso de compilación, puedes inicializarla directamente en el navegador:
<div data-fs-success></div>
<div data-fs-error></div>
<form id="my-form">
<label for="email">Email</label>
<input type="email" id="email" name="email" data-fs-field />
<span data-fs-error="email"></span>
<label for="message">Message</label>
<textarea id="message" name="message" data-fs-field></textarea>
<span data-fs-error="message"></span>
<button type="submit" data-fs-submit-btn>Submit</button>
</form>
<script>
window.formspree =
window.formspree ||
function () {
(formspree.q = formspree.q || []).push(arguments);
};
formspree('initForm', {
formElement: '#my-form',
formId: 'YOUR_FORM_ID',
});
</script>
<script src="https://unpkg.com/@formspree/ajax@1" defer></script>
Migrar desde código AJAX manual
Si previamente has enviado formularios con código personalizado de fetch, Axios o jQuery, @formspree/ajax te ofrece una alternativa más simple. En lugar de hacer manualmente:
- escuchar eventos de envío
- serializar los datos del formulario
- enviar solicitudes
- analizar los errores de validación
- actualizar el DOM para los estados de éxito y fallo
Puedes inicializar la biblioteca una vez y dejar que se encargue de esas piezas por ti.
Nota sobre frameworks
Esta biblioteca está diseñada para JavaScript estándar y formularios HTML estándar. Si estás usando React, consulta nuestra biblioteca de React en su lugar.