# Enviar formularios con JavaScript (AJAX)

> Formspree Docs · Crear tu formulario · 23 de marzo de 2026

#### Disponible en todos los planes

Puedes utilizar [`@formspree/ajax`](https://www.npmjs.com/package/@formspree/ajax)[](https://www.npmjs.com/package/@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:

```bash
npm install @formspree/ajax   # via npm, or
yarn add @formspree/ajax      # via yarn
```

E inicializa tu formulario en JavaScript:

```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>`:

```html
<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:

```html
<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 `id` de tu formulario coincida con el ID que pasaste como `formId` en la llamada a `initForm` del 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.

```html
<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.

```html
<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.

```html
<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.

```html
<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.

```html
<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-success` ni un manejador `onSuccess` personalizado, el formulario se reemplaza con un mensaje "Thank you!".
-   Si hay un elemento `data-fs-success` y no hay un manejador `onSuccess` personalizado, 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:

```javascript
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.

```javascript
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.

```javascript
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:

```javascript
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.

```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.

```javascript
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:

```javascript
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:

```html
<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:

```html
<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](/es/articles/working-with-react/the-formspree-react-library/) en su lugar.
