# El atributo action de un formulario HTML, explicado

> Qué hace el atributo action de un formulario, cómo se resuelven los valores relativos y vacíos, cómo formaction envía un formulario a dos sitios y por qué los hostings estáticos responden 405.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/html-form-submission/action-attribute

El atributo `action` es la URL a la que un formulario envía sus datos. Un valor relativo se resuelve respecto a la dirección de la página, uno vacío o ausente significa la propia página, y el `formaction` de un botón de envío lo sobrescribe para ese botón. En un sitio estático, ponle la URL completa de un backend de formularios como `https://ikiform.com/f/<formId>`, porque tu propio hosting no puede aceptar el POST.

La mayoría de formularios rotos en sitios estáticos fallan en este único atributo. El markup parece correcto, el botón funciona y el navegador muestra un `405` o una página en blanco, porque los datos fueron a un sitio que no puede recibirlos. Esta página muestra exactamente adónde envía los datos un `action` concreto, y luego usa `formaction` para dirigir un formulario a dos bandejas de entrada.

## Qué cambia aquí

`action` es una URL como cualquier `href`, con un matiz: un formulario sin `action` no deja de hacer nada, envía a la página en la que está. En un sitio renderizado en el servidor, esa página podría gestionar el envío. En un hosting estático no puede, así que un `action` ausente o relativo solo falla después de desplegar.

## Adónde envía los datos cada valor

Toma una página en `https://example.com/company/contact.html` con cinco formularios:

`contact.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<form action="/api/contact" method="post">
<form action="send" method="post">
<form action="" method="post">
<form method="post">
```

| action | Se resuelve como | En un hosting estático |
| --- | --- | --- |
| `https://ikiform.com/f/frm_...` | Exactamente esa URL | Funciona. Ikiform acepta el POST |
| `/api/contact` | `https://example.com/api/contact` | Solo funciona si tu hosting ejecuta una función en esa ruta |
| `send` | `https://example.com/company/send`, relativa a la carpeta | `405` o `404` |
| `""` (empty) | La propia página, `contact.html` | `405` en la mayoría de hostings estáticos |
| Ausente | La propia página | `405` en la mayoría de hostings estáticos |

Diagrama: Cómo convierte el navegador el atributo action de un formulario en la URL a la que envía

1. Un action absoluto se usa exactamente como está escrito, así que el envío llega a Ikiform, que responde con una redirección.
2. Un action relativo, vacío o ausente se resuelve respecto a la dirección de la propia página, o respecto a un elemento base si la página tiene uno.
3. El envío va entonces a tu propio hosting. Un hosting estático solo sirve archivos, así que rechaza el POST, normalmente con 405.

Si la barra de direcciones muestra tu propio dominio justo después de enviar, el action era relativo.

> Un elemento `<base href>` en el head de la página cambia cómo se resuelve cada URL relativa, incluido `action`. Algunos creadores de sitios y configuraciones de apps de una sola página añaden uno. Usa una URL completa y no importará.

### Comprueba qué usará el navegador

En la consola del navegador, el atributo y la propiedad son distintos. `getAttribute` devuelve lo que escribiste; la propiedad `action` devuelve la URL resuelta a la que el navegador enviará de verdad:

`Consola`:

```js
const form = document.querySelector("form");
form.getAttribute("action");
form.action;
```

Si `form.action` muestra tu propio dominio, ahí es adonde van los datos. Creadores como Webflow y Framer suelen poner el `action` desde su propio panel de ajustes, así que revisa la página publicada, no tu código fuente. Las [guías de creadores de sitios](https://ikiform.com/es/docs/guides/site-builders.md) indican dónde lo guarda cada creador.

## Un formulario, dos bandejas de entrada

El `formaction` de un botón de envío sustituye el `action` del formulario solo para ese botón. Aquí, un mismo conjunto de campos va a dos formularios de Ikiform. **Ask support** envía al formulario de soporte, **Talk to sales** al de ventas, y cada formulario de Ikiform manda email a sus propios destinatarios:

`contact.html`:

```html
<form action="https://ikiform.com/f/frm_supportxxxxxxxxx" method="post">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="message">How can we help?</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Ask support</button>
  <button formaction="https://ikiform.com/f/frm_salesxxxxxxxxxxx">Talk to sales</button>
</form>
```

- Cada formulario de Ikiform tiene sus propios destinatarios de notificaciones, ajustes de spam y webhooks, así que soporte y ventas nunca ven el correo del otro.
- Los dos formularios necesitan la misma definición de campos, o ninguna. Con campos definidos, un campo que un formulario no conoce se rechaza con `422`.
- Los demás atributos `form*` funcionan igual: `formmethod`, `formenctype`, `formnovalidate` y `formtarget`. Un botón **Save draft** con `formnovalidate` se salta las comprobaciones del navegador.
- `formaction` solo funciona en botones de envío: `<button>`, `<input type="submit">` e `<input type="image">`.

La alternativa es un único formulario de Ikiform con un campo `topic`, y enrutar por tema en un webhook o con los filtros de tu bandeja de entrada. Así mantienes una sola lista y una sola exportación. Dos formularios son más sencillos cuando los dos equipos no deberían compartir destinatarios en absoluto.

## action con query string

Con `method="get"`, el navegador sustituye la query string del action por los campos del formulario. El `lang=de` del primer formulario de abajo se descarta sin avisar; el segundo lo conserva como input oculto:

`search.html`:

```html
<form action="/search?lang=de" method="get">
  <input name="q" />
</form>

<form action="/search" method="get">
  <input name="q" />
  <input type="hidden" name="lang" value="de" />
</form>
```

Con `method="post"` la query string se conserva, porque los campos van en el cuerpo. Eso no cambia nada para Ikiform: los parámetros de query de la URL del endpoint no se guardan, así que usa inputs ocultos para los valores que quieras conservar.

## Inputs fuera del formulario

A veces el diseño necesita un input que no está dentro del elemento `<form>`, como un registro en el pie junto a otro contenido. El atributo `form` en un input o un botón lo une a un formulario por `id`, y envía al `action` de ese formulario:

`footer.html`:

```html
<form id="newsletter" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post"></form>

<footer>
  <input form="newsletter" name="email" type="email" required />
  <button form="newsletter">Subscribe</button>
</footer>
```

## Actions mailto: y javascript:

`action="mailto:you@example.com"` pide a la app de correo del visitante que abra un mensaje con los campos. No se envía nada salvo que tenga una app de correo configurada y pulse enviar, y nunca sabrás que lo intentó. `action="javascript:..."` ejecuta código en lugar de enviar y lo bloquean la mayoría de políticas de seguridad de contenido. Merece la pena sustituir ambos por un endpoint real.

## Comprueba que funciona

1. En **Allowed domains** del formulario, añade el dominio de tu sitio, y `localhost` mientras desarrollas. Déjalo vacío para aceptar envíos desde cualquier lugar.
2. Abre la página publicada, no tu código fuente, y ejecuta `document.querySelector("form").action` en la consola. Imprime tu URL completa de Ikiform.
3. Envía el formulario. El panel Network muestra un POST a `ikiform.com` respondido con `303`, no un POST a tu propio dominio.
4. En el formulario de dos bandejas, envía una vez con cada botón. Cada envío aparece bajo su propio formulario en el panel.
5. Revisa la bandeja de entrada de cada destinatario de las notificaciones. Cada uno recibe un email con los campos, y **Reply** va a quien envió el formulario cuando este tiene un campo `email`.

## Errores comunes

| Problema | Causa y solución |
| --- | --- |
| `405 Method Not Allowed` desde tu propio dominio | El action es relativo, está vacío o falta, así que el envío fue a tu hosting estático. Usa la URL completa de Ikiform |
| `404 not_found` desde ikiform.com | El id del formulario en el action es incorrecto, o el formulario se eliminó. Copia el endpoint desde la página del formulario en el panel |
| El creador sigue restableciendo el action | Algunos creadores controlan el `action` de su bloque de formulario. Usa su ajuste de action personalizado, o un embed con tu propio markup |
| El navegador avisa de que el formulario no es seguro | El action usa `http:` en una página `https:`. El endpoint de Ikiform es solo `https:`; corrige el esquema |
| También se envían campos de un segundo formulario | Los formularios no se pueden anidar. El navegador cierra el formulario exterior en la etiqueta `<form>` interior. Usa el atributo `form` en su lugar |

Para el flujo completo de un envío, del clic a la redirección, consulta el [resumen](https://ikiform.com/es/guides/html-form-submission.md#how-it-works). Todo lo que acepta el endpoint está en [Formularios HTML](https://ikiform.com/es/docs/html.md).

## Preguntas

### ¿Qué pasa si un formulario no tiene atributo action?

Envía a la página en la que está. Funciona cuando tu servidor gestiona envíos en esa URL, pero en un hosting estático falla, normalmente con 405 Method Not Allowed.

### ¿Cuál es la diferencia entre action y formaction?

action se pone en el formulario y se aplica a todos los envíos. formaction se pone en un botón de envío y sobrescribe action cuando se usa ese botón, así que un formulario puede enviar a dos sitios.

### ¿Puede el action del formulario ser una URL de otro dominio?

Sí. Los navegadores envían entre sitios sin ninguna configuración especial, que es como una página estática envía a un backend de formularios. El servidor que recibe decide si lo acepta; Ikiform comprueba el origen de la página con los dominios permitidos del formulario.

### ¿Por qué desaparecen los parámetros de la query string de la URL del action?

Con method get, el navegador sustituye la query string del action por los propios campos del formulario. Pasa cada parámetro a un input oculto. Con method post la query string se conserva.

## Más guías

- [Envío de formularios HTML](https://ikiform.com/es/guides/html-form-submission.md): Qué hace un navegador cuando se envía un formulario: qué campos envía, cómo los codifica, qué debería responder el servidor y cómo responde Ikiform.
- [Redirección tras el envío](https://ikiform.com/es/guides/html-form-submission/redirect-after-submit.md): Manda a los visitantes a tu propia página de agradecimiento cuando se envía un formulario: la redirección 303, el campo _redirect, qué dominios se permiten y qué pasa al recargar.
- [Sin recargar la página](https://ikiform.com/es/guides/html-form-submission/without-page-reload.md): Envía un formulario con fetch y FormData para que el visitante se quede en la página, con errores de campo, estado de carga, reintentos y un plan B cuando los scripts fallan.
- [Validación de formularios](https://ikiform.com/es/guides/html-form-submission/validation.md): Valida un formulario con required, type, pattern y min, da estilo a los errores con :user-invalid y aplica las mismas reglas en el servidor con definiciones de campos.
