Formularios
En resumen: Un formulario envía solo los campos que tienen name, la etiqueta <label> une el texto con el campo, y los atributos required, type, min, max y pattern hacen que el navegador compruebe lo escrito antes de enviarlo.
Problema
Un pedido sin datos
La tienda recibe pedidos sin nombre y sin teléfono. Los compradores juran que rellenaron todo. Aquí está el formulario de compra. Rellénalo y pulsa «Hacer el pedido».
Consola
El sandbox no envía nada por la red. En su lugar, la consola dice lo que se habría enviado: «El formulario se envió: (sin campos)». Todo lo que escribiste se quedó en la página. Hay también una segunda señal: un clic en la palabra «Nombre» no pone el cursor en el campo. En pantalla el texto y el campo están uno al lado del otro, pero nada en el árbol los une.
La idea
El formulario, el name y la etiqueta
Un formulario (<form>) reúne campos y los envía juntos. action dice adónde (/order), y method dice cómo (post).
<form action="/order" method="post"> <label for="phone">Teléfono</label> <input id="phone" name="phone" type="tel"> <button type="submit">Hacer el pedido</button></form>namees lo que se envía. Al enviar, el navegador hace un parname=valuepor cada campo que tiene nombre:phone=0888123456. Un campo sinnameno se envía, por lleno que esté. Por eso el pedido iba vacío.<label>es la etiqueta del campo. Se une confor, que apunta aliddel campo. El campo también puede ir dentro de la etiqueta:<label>Teléfono <input name="phone"></label>. Entonces no hace faltafor.
La etiqueta le da al campo un nombre en el árbol de accesibilidad. Un lector de pantalla dice «Teléfono, cuadro de texto», no solo «cuadro de texto». Un clic en la etiqueta pone el foco en el campo, y una casilla con etiqueta se puede marcar con su texto. Las comprobaciones de las tareas encuentran el campo por su etiqueta, como lo hace una persona.
id y name suelen ser iguales, pero hacen trabajos distintos. El id es para la etiqueta y para CSS, y el name es la clave en la petición.
La idea
Los tipos de campos
<input> es un campo, y type dice qué es:
text(el predeterminado),email,tel: texto. En el móvilemailytelabren un teclado con@o con dígitos.number: un número, con flechas.min="1",max="10"ystep="1"dan los límites y el paso.checkbox: una marca de sí o no. Se envía solo cuando está marcada:gift=yesporvalue="yes". Sinvalueenvíagift=on.radio: una opción entre varias. Los botones de opción forman un grupo por unnamecompartido:name="delivery"en los dos, yvaluedice cuál está elegido. Solo se envía el elegido.
Otros campos:
<select>con<option>: un menú desplegable. Envía elvaluede la opción elegida, o su texto cuando no hayvalue.<textarea>: texto en varias líneas, como una nota para el repartidor.<fieldset>con<legend>: un grupo de campos con un título. Los botones de opción de la entrega están en unfieldset, y lalegend«Entrega» es el nombre del grupo. Sin ella un lector de pantalla dice «A una sucursal», pero no para qué es la sucursal.
El botón. <button type="submit"> envía el formulario. <button type="button"> no hace nada por sí solo, y su acción está en JavaScript. Dentro de un formulario un <button> sin type es submit. Así que escribe siempre el type.
Míralo
La compra completa
El formulario de compra con todos los tipos de campos. Rellénalo, cambia la ciudad y la entrega y pulsa «Hacer el pedido». Marca «Envolver para regalo» y pulsa otra vez.
Consola
Mira la línea de la consola. Los pares están en el orden de los campos del código. La ciudad es plovdiv: se envía el value, no el texto «Plovdiv». De la entrega solo está el botón elegido. La casilla falta mientras no se marca. La nota vacía se envía como note=: un campo vacío con nombre sigue siendo un campo.
Pruébalo
Arregla la compra
Arregla el formulario del principio para que el pedido llegue completo. Los textos «Nombre», «Teléfono» y «Dirección» pasan a ser las etiquetas de sus campos, y los campos reciben los nombres name, phone y address.
Consola
Solución
index.html<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Finalizar compra · La tienda</title>
</head>
<body>
<h1>Finalizar compra</h1>
<form action="/order" method="post">
<label for="name">Nombre</label>
<input id="name" name="name">
<label for="phone">Teléfono</label>
<input id="phone" name="phone" type="tel">
<label for="address">Dirección</label>
<input id="address" name="address">
<button type="submit">Hacer el pedido</button>
</form>
</body>
</html>
Cada <p> pasa a ser un <label for="…"> que apunta al id de su campo, y cada campo recibe un name. La comprobación encuentra los campos por sus etiquetas, escribe en ellos y lee la línea de la consola: name=María López, phone=0888123456, address=Calle Mayor 7. Si for apunta a un id que no existe, la etiqueta es solo texto y el campo no se encuentra.
Pruébalo
Encuentra el error
La compradora escribe un código de descuento y pulsa «Aplicar el código». El pedido se envía antes de que haya escrito su correo electrónico. ¿Qué línea tiene la culpa?
Elige la línea con el error.
El <button> de la línea 3 no tiene type, y dentro de un formulario eso significa submit. Un clic en él envía todo el formulario. Debe ser <button type="button">, y el código de descuento se aplica con JavaScript.
Pruébalo
Completa
¿Qué atributo de la etiqueta apunta al id del campo?
<label ="email">Correo electrónico</label>
<input id="email" name="email" type="email">for: la etiqueta es «para» el campo con este id. Sin él (y sin el campo dentro de la etiqueta) los dos no están unidos.
La idea
Las comprobaciones del navegador
Un pedido con el correo ana o con una cantidad de 0 no debería enviarse. El navegador puede comprobar mucho por sí solo, sin una línea de JavaScript. Las reglas son atributos del campo:
required: el campo no puede estar vacío. En una casilla: debe estar marcada. En un grupo de botones de opción: algo debe estar elegido.type="email": el texto debe parecer un correo electrónico (nombre@dominio). Un campo vacío pasa si no hayrequired.minymax: los límites de un número.stepes el paso: constep="1", 2,5 no pasa.minlengthymaxlength: cuántos caracteres como mínimo y como máximo.pattern: un patrón para todo el texto, como una expresión regular.pattern="0[0-9]{9}"es un 0 y nueve dígitos más.
Cuando se pulsa «Hacer el pedido», el navegador comprueba cada campo. Si uno no pasa, el formulario no se envía y el evento submit no llega a ocurrir. El navegador pone el foco en el primer campo no válido y muestra al lado un mensaje en el idioma del navegador. La compradora lo corrige, pulsa otra vez, y el navegador comprueba desde el principio.
novalidate en el <form> desactiva estas comprobaciones. Se usa cuando la página comprueba y muestra los errores con su propio código. De eso trata la lección sobre formularios en componentes.
Míralo
Mira qué pasa con «Hacer el pedido»
El código es un formulario de compra corto. Fíjate en el orden: primero la comprobación, luego el evento, luego la recogida.
<form action="/order" method="post"> <label>Nombre <input name="name" required></label> <label>Correo <input name="email" type="email" required></label> <label>Teléfono <input name="phone" pattern="0[0-9]{9}"></label> <label>Cantidad <input name="qty" type="number" min="1" max="10"></label> <label><input name="gift" type="checkbox"> Regalo</label> <button>Hacer el pedido</button></form>Paso a paso, en palabras
- El comprador pulsa «Hacer el pedido». El <button> no tiene type, así que dentro de un formulario es un botón de envío. El navegador todavía no envía nada.
- Primero comprueba cada campo, en el orden del código, contra sus reglas. «iva» no es un correo electrónico, y «12345» no cumple el patrón.
- Hay campos no válidos, así que el evento submit no ocurre. El navegador pone el foco en el primer campo no válido y muestra un mensaje solo para él.
- El comprador corrige el correo y el teléfono y pulsa otra vez.
- La misma comprobación desde arriba. Esta vez todos los campos pasan.
- Solo ahora ocurre el evento submit. Si el código no lo detiene, el navegador envía el formulario a la dirección de action con el método de method.
- Recoge un par name=value de cada campo con nombre. La casilla sin marcar no se envía en absoluto.
- Con method="post" los pares van en el cuerpo de la petición, unidos con &. La clave es el atributo name, no el texto de la etiqueta.
El navegador comprueba todos los campos, pero muestra un mensaje solo para el primero no válido. Por eso una compradora a veces corrige un campo y enseguida ve un mensaje para el siguiente. Y gift no se envía en absoluto: para el servidor una casilla sin marcar y un campo que falta son lo mismo.
Pruébalo
Añade las comprobaciones
El pedido rápido del pan deja pasar todo. Añade comprobaciones: la cantidad va de 1 a 10, el correo electrónico es obligatorio y debe ser un correo, el teléfono es obligatorio y es un 0 y nueve dígitos más. La comprobación escribe 12, un correo vacío, «iva», un teléfono vacío y uno incorrecto, y espera que el navegador se detenga en el campo correcto.
Consola
Solución
index.html<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Cantidad · La tienda</title>
</head>
<body>
<h1>Pedido rápido: Pan Dobrudzha, 1,80 €</h1>
<form action="/order" method="post">
<p><label>Cantidad <input name="qty" type="number" value="1" min="1" max="10"></label></p>
<p><label>Correo electrónico <input name="email" type="email" required></label></p>
<p><label>Teléfono <input name="phone" type="tel" required pattern="0[0-9]{9}"></label></p>
<button type="submit">Hacer el pedido</button>
</form>
</body>
</html>
La cantidad recibe min="1" max="10", el correo type="email" required, y el teléfono required pattern="0[0-9]{9}". La comprobación pulsa «Hacer el pedido» después de cada error y mira dónde está el foco: dónde se detuvo el navegador. Si falta una regla, el formulario se envía y el foco no está en el campo. Al final, con los valores correctos, la consola dice qty=2, email=iva@example.com, phone=0888123456.
Más precisamente, para curiosos
El servidor comprueba otra vez. La comprobación del navegador es una comodidad para la compradora: ve el error enseguida. No protege la tienda. novalidate, el panel Elements o una petición enviada sin navegador la saltan, así que el servidor comprueba cada campo otra vez. Por qué es así se explica en la lección «Entrada no confiable».
Qué no se envía. Un campo sin name, una casilla sin marcar, un botón de opción no elegido y un campo con disabled. Un campo con readonly sí se envía: solo que no se puede cambiar. Los archivos (type="file") necesitan method="post" y enctype="multipart/form-data".
Cómo se envía. Con method="get" (el predeterminado) los pares van en la dirección: /order?name=…&phone=…. Con method="post" van en el cuerpo de la petición. En ambos casos se codifican: @ pasa a ser %40, y un espacio pasa a ser +.
Enter. Enter en un campo de texto envía el formulario como un clic en el botón de envío, con las mismas comprobaciones.
minlength y un valor desde código. minlength comprueba solo el texto que escribió una persona. Un valor del atributo value o de JavaScript pasa, aunque sea corto.
Sin comprobaciones. formnovalidate en un botón envía sin comprobar (por ejemplo, «Guardar borrador»). form.submit() desde JavaScript tampoco comprueba y no dispara el evento submit, mientras que form.requestSubmit() hace todo lo que hace un clic.
Dar estilo a los errores. CSS ve los campos no válidos con :invalid, y :user-invalid los detecta solo después de que una persona los ha tocado. Así un campo no está en rojo antes de que la compradora haya escrito nada. El módulo siguiente trata de CSS.
autocomplete. autocomplete="email", "tel", "name", "street-address" le dicen al navegador qué ofrecer de lo que recuerda. La compradora rellena la compra con dos clics.
Ejercicio
El formulario de compra
Haz desde cero el formulario de compra, con los campos en este orden. «Nombre» (name), obligatorio. «Correo electrónico» (email), un correo obligatorio. «Teléfono» (phone), obligatorio, un 0 y nueve dígitos más. «Ciudad» (city): un menú desplegable Sofía, Plovdiv, Varna con los valores sofia, plovdiv, varna. Un grupo «Entrega» con dos botones de opción (delivery): «A la dirección» (address), elegido al principio, y «A una sucursal» (office). «Nota para el repartidor» (note), en varias líneas. Una casilla «Envolver para regalo» (gift) con el valor yes. Un botón «Hacer el pedido».
Consola
Solución
index.html<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Finalizar compra · La tienda</title>
</head>
<body>
<h1>Finalizar compra</h1>
<form action="/order" method="post">
<p><label>Nombre <input name="name" required></label></p>
<p><label>Correo electrónico <input name="email" type="email" required></label></p>
<p><label>Teléfono <input name="phone" type="tel" required pattern="0[0-9]{9}"></label></p>
<p>
<label for="city">Ciudad</label>
<select id="city" name="city">
<option value="sofia">Sofía</option>
<option value="plovdiv">Plovdiv</option>
<option value="varna">Varna</option>
</select>
</p>
<fieldset>
<legend>Entrega</legend>
<label><input type="radio" name="delivery" value="address" checked> A la dirección</label>
<label><input type="radio" name="delivery" value="office"> A una sucursal</label>
</fieldset>
<p><label>Nota para el repartidor <textarea name="note"></textarea></label></p>
<p><label><input type="checkbox" name="gift" value="yes"> Envolver para regalo</label></p>
<button type="submit">Hacer el pedido</button>
</form>
</body>
</html>
Cada campo está en su propio <label>, para que la comprobación lo encuentre por su texto. El teléfono es type="tel" con required y pattern, y el nombre vacío detiene el primer «Hacer el pedido». La ciudad es un <select> con un value en cada opción: si no, se envía «Plovdiv», no plovdiv. Los botones de opción están en un <fieldset> con <legend>Entrega</legend>, comparten name="delivery", y checked elige el primero. La nota es una <textarea>. La comprobación rellena todo, elige «A una sucursal», marca el regalo y lee la línea de la consola.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: El documento HTML · Texto, enlaces, imágenes, tablas
- Continúa en: Accesibilidad · Selectores y la cascada · Flexbox: fila y columna · El DOM: la página desde JavaScript
- Ejercicios sobre el tema: HTML: la estructura de la página