La mayoría de los sitios y las aplicaciones incluyen un formulario web. Los sitios de bromas, como DoWebsites<form>
.
El elemento HTML <form>
identifica un punto de referencia de documento que contiene controles interactivos para enviar información. Anidado en un <form>
, encontrarás todos los controles de formulario interactivos (y no interactivos) que lo componen.
El HTML es potente. En esta sección, se enfoca en la potencia de HTML y se explica lo que puede hacer sin agregar JavaScript. El uso de datos de formulario del cliente para actualizar la IU de alguna manera suele implicar CSS o JavaScript, que no se analizan aquí. Hay un curso completo de Aprende Formularios. No duplicaremos esa sección aquí, pero presentaremos varios controles de formulario y los atributos HTML que los potencian.
Con los formularios, puedes permitir que los usuarios interactúen con tu sitio web o aplicación, validen la información ingresada y envíen los datos a un servidor. Los atributos HTML pueden permitir que el usuario seleccione controles de formulario o ingrese un valor. Los atributos HTML pueden definir criterios específicos con los que el valor debe coincidir para ser válido. Cuando el usuario intenta enviar el formulario,
todos los valores de control del formulario pasan por la validación de restricciones del cliente y pueden impedir el envío
hasta que los datos coincidan con los criterios requeridos, todo sin JavaScript. También puedes desactivar esta función: configurar el atributo novalidate
en <form>
o, con mayor frecuencia, formnovalidate
en un botón, guardar los datos del formulario para completarlos más adelante evita la validación.
Cómo enviar formularios
Los formularios se envían cuando el usuario activa un botón de envío anidado en él. Cuando se usa <input>
para botones, el "valor" es la etiqueta del botón y se muestra en él. Cuando usas <button>
, la etiqueta es el texto entre las etiquetas de apertura y cierre de <button>
. Un botón de envío se puede escribir de dos maneras:
<input type="submit" value="Submit Form">
<button type="submit">Submit Form</button>
Para un formulario muy simple, necesitas un elemento <form>
, con algunas entradas de formulario y un botón de envío. Sin embargo, enviar un formulario es mucho más que eso.
Los atributos del elemento <form>
establecen el método HTTP mediante el cual se envía el formulario y la URL que procesa el envío del formulario. Sí, los formularios se pueden enviar, procesar y cargar una página nueva sin ningún JavaScript. El elemento <form>
es así de potente.
Los valores de los atributos action
y method
del elemento <form>
definen la URL que procesa los datos del formulario y el método HTTP que se usa para enviar los datos, respectivamente.
De forma predeterminada, los datos del formulario se envían a la página actual. De lo contrario, configura el atributo action
con la URL a la que se deben enviar los datos.
Los datos enviados se componen de pares nombre/valor de los diversos controles de formularios del formulario. De forma predeterminada, se incluyen todos los controles de formulario anidados que tienen un name
. Sin embargo, con el atributo form
, es posible incluir controles de formularios fuera de <form>
y omitir los controles de formularios anidados dentro de <form>
. Compatible con controles de formulario y <fieldset>
, el atributo form
toma como valor el id
del formulario con el que está asociado el control, no necesariamente el formulario en el que está anidado. Esto significa que los controles de formulario no necesitan anidarse físicamente en un <form>
.
El atributo method
define el protocolo HTTP de la solicitud: generalmente, GET
o POST
. Con GET
, los datos del formulario se envían como una cadena de parámetros de pares name=value
, que se agrega a la URL de action
.
Con POST
, los datos se adjuntan al cuerpo de la solicitud HTTP. Cuando envíes datos seguros, como contraseñas y información de tarjetas de crédito, usa siempre POST
.
También existe un método DIALOG
. Si un <form method="dialog">
está dentro de una <dialog>
, el envío del formulario cerrará el diálogo;
hay un evento de envío aunque los datos no se borren ni se envíen. Una vez más, sin JavaScript. Esto se analiza en la sección de diálogo. Ten en cuenta que, como esto no envía el formulario, es probable que desees
incluir formmethod="dialog"
y formnovalidate
en el botón de envío.
Los botones de formulario pueden tener más atributos que los descritos al comienzo de esta sección. Si el botón incluye un atributo formaction
, formenctype
, formmethod
, formnovalidate
o formtarget
, los valores establecidos en el botón que activa el envío del formulario tienen prioridad sobre los action
, enctype
, method
y target
establecidos en <form>
. La validación de la restricción se realiza antes del envío del formulario, pero solo si no hay un formnovalidate
en el botón de envío activado ni una novalidate
en el <form>
.
A fin de capturar qué botón se usó para enviar un formulario, asígnale una name
. Los botones sin nombre ni valor no se envían con los datos del formulario cuando se envía el formulario.
Después de enviar el formulario
Cuando el usuario envía un formulario en línea completado, se envían los nombres y valores de los controles de formulario correspondientes. El nombre es el valor del atributo name
. Los valores provienen del contenido del atributo value
o del valor que ingresó o eligió el usuario. El valor de un <textarea>
es su texto interno.
El valor de un <select>
es el value
del <option>
seleccionado o, si el <option>
no incluye un atributo value
, el valor es el texto interno de la opción seleccionada.
<form method="GET">
<label for="student">Pick a student:</label>
<select name="student" id="student">
<option value="hoover">Hoover Sukhdeep</option>
<option>Blendan Smooth</option>
<option value="toasty">Toasty McToastface</option>
</select>
<input type="submit" value="Submit Form">
</form>
Si seleccionas "Hoover Sukhdeep" (o no haces nada, ya que el navegador muestra y, por lo tanto, selecciona el primer valor de la opción de forma predeterminada) y, luego, haz clic en el botón Enviar para volver a cargar esta página y se configurará la URL de la siguiente manera:
https://web.dev/learn/html/forms?student=hoover
Debido a que la segunda opción no tiene un atributo value
, el texto interno se envía como el valor. Si seleccionas "Combinean Smooth" y haces clic en el botón Enviar, se volverá a cargar la página y se configurará la URL de la siguiente manera:
https://web.dev/learn/html/forms?student=Blendan+Smooth
Cuando se envía un formulario, la información enviada incluye los nombres y valores de todos los controles de formulario nombrados que tienen un name
, excepto las casillas de verificación no seleccionadas, los botones de selección no seleccionados y los nombres y valores de cualquier botón que no sea el que envió el formulario. Para todos los demás controles de formulario, si el control de formulario tiene un nombre, pero no se ingresó ningún valor o no se estableció un valor predeterminado, el name
del control de formulario se envía con un valor vacío.
Hay 22 tipos de entradas, por lo que no podemos abarcarlos todos.
Ten en cuenta que incluir un valor es opcional y, a menudo, no es una buena idea cuando deseas que el usuario ingrese información.
Para los elementos <input>
en los que el usuario no puede editar el valor, siempre debes incluir un valor, incluso para los elementos de entrada con un tipo de hidden
, radio
, checkbox
, submit
, button
y reset
.
El uso de name
únicos para los controles de formulario simplifica el procesamiento de datos del servidor y se recomienda. Las casillas de verificación y los botones de selección son excepciones a esta regla.
Botones de selección
Si alguna vez notaste que, cuando seleccionas un botón de selección dentro de un grupo de botones de selección, solo se puede seleccionar uno a la vez, esto se debe al atributo name
. Para crear este efecto de solo-se-puede-seleccionar-uno, se le asigna a cada botón de selección
de un grupo el mismo name
.
Un name
debe ser único para el grupo: si usas accidentalmente el mismo name
para dos grupos separados, seleccionar un botón de selección en el segundo grupo anulará cualquier selección realizada en el primer grupo con el mismo name
.
El name
junto con el value
del botón de selección seleccionado se envían con el formulario. Asegúrate de que cada botón de selección tenga un value
relevante (y, por lo general, único). No se envían los valores de los botones de selección no seleccionados.
Puedes tener tantos grupos de radio en una página como desees, con cada grupo funcionando de forma independiente, siempre que cada uno tenga un name
único para el grupo.
Si deseas cargar la página con uno de los botones de selección de un grupo con el mismo nombre seleccionado, incluye el atributo checked
.
Este botón de selección coincidirá con la pseudoclase CSS :default
, incluso si el usuario selecciona un botón de selección diferente. El botón de selección seleccionado actualmente coincide con la pseudoclase :checked
.
Si el usuario debe elegir un control de selección de un grupo de botones de selección, agrega el atributo required
a al menos uno de los controles. Si incluyes required
en un botón de selección de un grupo, se requiere una selección para enviar el formulario, pero no tiene que ser el botón de selección con el atributo que se selecciona para que sea válido. Además, indica claramente en el <legend>
que el control de formulario es obligatorio. Más adelante, se describe el etiquetado de grupos de botones de selección junto con cada botón individual.
Casillas de verificación
Es válido que todas las casillas de verificación de un grupo tengan el mismo name
. Solo las casillas de verificación seleccionadas tienen sus name
y value
enviados con el formulario. Si tienes varias casillas de verificación con el mismo nombre seleccionadas, se enviará el mismo nombre con valores diferentes (con suerte). Si tienes varios controles de formulario con el mismo nombre, incluso si no son todos cuadros de verificación, todos se enviarán separados por símbolos &.
Si no incluyes un value
en una casilla de verificación, el valor de las casillas de verificación seleccionadas será on
de forma predeterminada, lo que probablemente no sea útil. Si tienes tres casillas de verificación llamadas chk
y están todas marcadas, no se podrá descifrar el envío del formulario:
https://web.dev/learn/html/forms?chk=on&chk=on&chk=on
Para que una casilla de verificación sea obligatoria, agrega el atributo required
. Siempre informa al usuario cuándo debe marcarse una casilla de verificación o cuándo se requiere algún control de formulario. Agregar required
a una casilla de verificación solo hace que esa casilla sea obligatoria; no afecta a otras casillas de verificación con el mismo nombre.
Etiquetas y conjuntos de campos
Para que los usuarios sepan cómo completar un formulario, este debe ser accesible. Cada control de formulario debe tener una etiqueta.
También quieres etiquetar grupos de controles de formulario. Mientras que las áreas de entrada, selección y texto individuales se etiquetan con <label>
, los grupos de controles de formulario se etiquetan según el contenido de <legend>
de <fieldset>
que los agrupa.
En los ejemplos anteriores, es posible que hayas notado que cada control de formulario, excepto el botón Enviar, tenía un <label>
. Las etiquetas proporcionan controles de formulario con nombres accesibles. Los botones obtienen su nombre accesible de su contenido o valor. Todos los demás controles de formulario requieren un <label>
asociado. Si no hay una etiqueta asociada, el navegador seguirá renderizando los controles de tu formulario, pero los usuarios no sabrán qué información se espera.
Para asociar explícitamente un control de formulario con un <label>
, incluye el atributo for
en <label>
: el valor es el id
del control de formulario con el que está asociado.
<label for="full_name">Your name</label>
<input type="text" id="full_name" name="name">
Asociar etiquetas con controles de formularios tiene varios beneficios. Las etiquetas permiten que los usuarios de lectores de pantalla accedan a los controles de formularios, ya que proporcionan un nombre de accesibilidad al control. Las etiquetas también son "áreas de impacto", ya que aumentan el área y hacen que el sitio sea más fácil de usar para los usuarios con problemas de destreza. Si usas un mouse, haz clic en cualquier parte de la etiqueta "Tu nombre". De esta manera, se enfoca la entrada.
Para proporcionar etiquetas implícitas, incluye el control de formulario entre las etiquetas <label>
de apertura y cierre. Se puede acceder de igual manera desde la perspectiva del lector de pantalla y del dispositivo de puntero, pero no proporciona el gancho de diseño como la etiqueta explícita.
<label>Your name
<input type="text" name="name">
</label>
Como las etiquetas son "áreas de impacto", no incluyas elementos interactivos dentro de una etiqueta explícita ni ningún otro componente interactivo que no sea el control de formulario etiquetado en una etiqueta implícita. Por ejemplo, si incluyes un vínculo en una etiqueta, mientras que el navegador renderizará el código HTML, los usuarios se confundirán si hacen clic en la etiqueta para ingresar un control de formulario, pero se los redirecciona a una página nueva.
Por lo general, el <label>
va antes del control de formulario, excepto en el caso de los botones de selección y las casillas de verificación. Esto no es obligatorio.
Es solo el patrón de UX común. La serie de Formularios de aprendizaje contiene información sobre el diseño de formularios.
En el caso de los grupos de botones de selección y casillas de verificación, la etiqueta proporciona el nombre accesible para el control de formulario con el que está asociado, pero el grupo de controles y sus etiquetas también necesitan una etiqueta. Para etiquetar el grupo, agrupa todos los elementos en un <fieldset>
, con el <legend>
que proporciona la etiqueta para el grupo.
<fieldset>
<legend>Who is your favorite student?</legend>
<ul>
<li>
<label>
<input type="radio" value="blendan" name="machine"> Blendan Smooth
</label>
</li>
<li>
<label>
<input type="radio" value="hoover" name="machine"> Hoover Sukhdeep
</label>
</li>
<li>
<label>
<input type="radio" value="toasty" name="machine"> Toasty McToastface
</label>
</li>
</ul>
</fieldset>
En este ejemplo, el <label>
implícito asigna cada etiqueta a un botón de selección y el <legend>
proporciona la etiqueta para el grupo de botones de selección.
Anidar un <fieldset>
dentro de otro <fieldset>
es una práctica estándar. Por ejemplo, si un formulario es una encuesta de muchas preguntas divididas en grupos de preguntas relacionadas, la <fieldset>
del "estudiante favorito" puede estar anidada en otra <fieldset>
etiquetada como "Tus favoritos":
<fieldset>
<legend>Your favorites:</legend>
<ul start="6">
<li>
<fieldset>
<legend>Who is your favorite student?</legend>
<ul>
<li>
<!-- the rest of the code here -->
El aspecto predeterminado de estos elementos ha provocado que se usen poco, pero <legend>
y <fieldset>
se pueden diseñar con CSS.
Además de todos los atributos globales, <fieldset>
también admite los atributos name
, disabled
y form
.
Cuando inhabilitas un conjunto de campos, se inhabilitan todos los controles de formularios anidados. Ni los atributos name
ni form
tienen mucho uso en <fieldset>
. Se puede usar name
para acceder al fieldset con JavaScript, pero el fieldset en sí no se incluye en los datos enviados (se incluyen los controles de formulario nombrados anidados dentro).
Tipos de entrada y teclado dinámico
Como se mencionó antes, hay 22 tipos diferentes de entradas.
En algunos casos, cuando un usuario está en un dispositivo con un teclado dinámico que se muestra solo cuando es necesario, como un teléfono, el tipo de entrada que se usa determina el tipo de teclado que se muestra. El teclado predeterminado que se muestra se puede optimizar para el tipo de entrada requerida.
Por ejemplo, si escribes tel
, se mostrará un teclado optimizado para ingresar números de teléfono; email
incluye @
y .
, y el teclado dinámico para url
incluye un dos puntos y el símbolo de barra. Lamentablemente, el iPhone aún no incluye :
en el teclado dinámico predeterminado para los tipos de entrada url
.
Teclado para <input type="tel">
en iPhone y dos teléfonos Android diferentes: