Skip to content
This page has been auto-translated and may contain errors.View in English

Formularios e inputs

docs.scrimba.com

Casi todos los sitios web que hacen algo por ti, un cuadro de búsqueda, un inicio de sesión, una compra, un campo de comentarios, está construido sobre un formulario. Un formulario es cómo una página deja de hablar al visitante y comienza a escuchar: recopila lo que alguien escribe, marca o selecciona, y entrega esos datos para que se actúe sobre ellos. Este capítulo trata sobre el HTML que hace que eso sea posible.

El elemento form

Un formulario es un contenedor que agrupa las cosas que un visitante completa. Envuelves tus inputs y un botón dentro de un elemento <form>, y el trabajo del formulario es reunir todo y enviarlo cuando el visitante haya terminado.

html
<form>
  <label>Tu nombre</label>
  <input>
  <button>Enviar</button>
</form>

Piénsalo como un formulario de papel que completas en la oficina de un médico. La hoja contiene todos los cuadros, escribes en cada uno, y al final entregas toda la hoja de una vez. El elemento <form> es esa hoja.

Un <form> es el contenedor que recopila sus controles y los envía como un paquete único. Dos atributos deciden qué pasa al enviar: action es la dirección a la que se envían los datos, y method es cómo se envían.

html
<form action="/subscribe" method="post">
  <label for="email">Dirección de correo</label>
  <input id="email" name="email" type="email">
  <button type="submit">Suscribirse</button>
</form>

Cuando el visitante activa un envío, el navegador recopila cada control nombrado dentro del formulario, empaqueta los valores, y envía una solicitud a la dirección action. No tienes que configurar nada de eso tú mismo. El elemento <form> te da este comportamiento de forma gratuita, por eso agrupar controles en un formulario real es mejor que esparcir inputs sueltos en la página.

Un <form> es un mecanismo de envío nativo: el comportamiento integrado del navegador que recopila los controles del formulario en una solicitud y la envía, sin necesidad de escritura de scripts. Al enviar, el navegador lee el action (la URL a la que va la solicitud) y method (get o post, cubiertos más adelante en este capítulo), serializa los controles en la solicitud, y navega. Ese comportamiento predeterminado es la razón por la que un formulario aún funciona con JavaScript deshabilitado o aún no cargado, que es la línea base desde la que construyes en lugar de la cosa que reemplazas.

html
<form action="/subscribe" method="post">
  <label for="email">Dirección de correo</label>
  <input id="email" name="email" type="email">
  <button type="submit">Suscribirse</button>
</form>

Dos comportamientos confunden a la gente. Primero, un formulario se envía en Enter cuando el enfoque está en un campo de texto de una sola línea, no solo en un clic de botón, así que el envío por teclado está integrado y vale la pena probar. Segundo, el envío predeterminado recarga o navega la página; cuando manejas un formulario con JavaScript llamas a event.preventDefault() para detener esa navegación y tomar el control. Trata el envío nativo como el piso: debe hacer algo sensato incluso antes de que cualquier script se ejecute. Mejora progresiva, superposición de script sobre HTML funcional, es la razón para empezar aquí.

JunoEl elemento form Un <form> es el contenedor que sostiene tus inputs y un botón, y envía todo junto cuando alguien lo envía. Imagina el formulario de papel en un escritorio: una hoja, muchos cuadros, entregada toda de una vez. Envuelve tus campos en un formulario y obtienes ese comportamiento de recopilación y envío sin hacer nada inteligente.
JunoEl elemento form El <form> agrupa sus controles y los envía; action dice dónde, method dice cómo. Obtienes la recopilación y el envío de forma gratuita, así que recurre a un formulario real en lugar de inputs sueltos más tu propio manejador de clic. Te ahorra código y funciona antes de que cualquier script se cargue.
JunoEl elemento form El envío nativo recopila los controles y envía una solicitud a action sin script involucrado, que es exactamente por qué un formulario aún funciona cuando JavaScript está apagado. Recuerda que se envía en Enter en un campo de texto, no solo en un clic. Cuando sí tomas el control con JavaScript, event.preventDefault() detiene la navegación predeterminada, y el formulario simple debajo sigue siendo tu red de seguridad.

Inputs y etiquetas

Un <input> es el cuadro en el que un visitante escribe. Por sí solo, sin embargo, un input es un cuadro vacío sin idea de para qué es. Eso es para lo que sirve una etiqueta: es el bit de texto que le dice al visitante qué poner en el cuadro.

html
<label for="city">Ciudad</label>
<input id="city">

Cada input necesita una etiqueta. Conectas los dos dándole al input un id y apuntando la etiqueta a él con for, usando la misma palabra en ambos. Una vez que están vinculados, hacer clic en la etiqueta coloca el cursor en el cuadro, que es una pequeña amabilidad que hace que el formulario sea más fácil de usar para todos.

Un <input> recopila un único valor; una <label> lo nombra. Los asocias haciendo coincidir el atributo for de la etiqueta con el id del input:

html
<label for="username">Nombre de usuario</label>
<input id="username" name="username" type="text" required>

Algunos atributos se ganan su lugar en la mayoría de los inputs. name es la clave bajo la que se envía el valor (cubierto en la sección de nomenclatura). required bloquea el envío hasta que el campo esté completo. placeholder muestra texto de pista tenue dentro del cuadro, pero un placeholder no es una etiqueta: desaparece en el momento en que alguien escribe, así que no puede reemplazar lo real. Cada input aún necesita su propia <label>.

Hay dos formas de asociar una <label> con su control, y la distinción importa para la accesibilidad. La primera es asociación explícita: la etiqueta tiene un atributo for cuyo valor es igual al id del control. La segunda es asociación implícita: envuelves el control dentro del elemento label, y no se necesita for o id.

html
<!-- explícito: for coincide con id -->
<label for="phone">Teléfono</label>
<input id="phone" name="phone" type="tel">

<!-- implícito: el input está dentro de la label -->
<label>
  Teléfono
  <input name="phone" type="tel">
</label>

Ambos dan al control un nombre accesible, el texto que un lector de pantalla anuncia cuando el campo obtiene enfoque, así que un visitante que no pueda ver el diseño aún sabe qué escribir. Prefiere la asociación explícita: sobrevive a los diseños CSS que alejan la etiqueta del input, y funciona cuando el estilo obliga a los dos a separarse. Un campo sin una etiqueta asociada se anuncia como un cuadro de edición desnudo sin propósito, que es uno de los fallos de accesibilidad más comunes en la web. El capítulo de accesibilidad profundiza más en esto.

JunoInputs y etiquetas El <input> es el cuadro en el que la gente escribe, y la <label> es el texto que les dice qué va ahí. Vincúlalos con for e id coincidentes y hacer clic en la etiqueta salta directamente al cuadro. Dale una etiqueta a cada input; un cuadro solitario sin palabras al lado solo confunde a la gente.
JunoInputs y etiquetas Haz coincidir el for de la etiqueta con el id del input y los dos están vinculados. Confía en required para bloquear envíos vacíos, pero no dejes que un placeholder reemplace una etiqueta: desaparece en el segundo en que alguien escribe. Etiqueta real, cada campo, sin excepciones.
JunoInputs y etiquetas Dos formas de vincular una etiqueta: for coincidiendo con id, o envuelve el input dentro de la etiqueta. Ambas dan al campo un nombre accesible, el texto que un lector de pantalla lee, y for/id explícito es la opción más robusta cuando CSS separa las cosas. Un campo sin etiqueta se lee como un cuadro sin nombre, que es uno de los errores de accesibilidad más comunes por ahí.

Otros controles

No todo es un cuadro de texto simple. Algunas preguntas se responden mejor marcando, eligiendo o seleccionando de una lista. Un cuadro de verificación (una casilla de verificación) es un interruptor de encendido o apagado, y un desplegable permite que alguien elija una opción entre varias.

html
<label>
  <input type="checkbox"> Enviarme el boletín
</label>

<label for="size">Tamaño</label>
<select id="size">
  <option>Pequeño</option>
  <option>Mediano</option>
  <option>Grande</option>
</select>

No tienes que memorizar esto. El punto por ahora es que un formulario puede hacer sus preguntas de cualquier forma que se ajuste: escríbela, márcala o elige de una lista.

El elemento <input> cambia de forma según su atributo type, y el tipo correcto te da un mejor teclado, validación integrada, y un selector nativo de forma gratuita:

html
<input type="email">     <!-- valida la forma @, teclado de correo en móvil -->
<input type="number">    <!-- teclado numérico, botones arriba/abajo -->
<input type="password">  <!-- enmascarada los caracteres -->
<input type="date">      <!-- selector de fecha nativo -->
<input type="checkbox">  <!-- un único interruptor de encendido/apagado -->
<input type="radio">     <!-- elige uno de un grupo -->

Más allá de <input>, tres elementos cubren el resto. <textarea> es un cuadro de texto de múltiples líneas para escritura más larga. <select> con hijos <option> es una lista desplegable. Y cuando necesitas campos relacionados agrupados visualmente y semánticamente, envuélvelos en un <fieldset> con una <legend> que nombre el grupo:

html
<fieldset>
  <legend>Velocidad de entrega</legend>
  <label><input type="radio" name="speed" value="standard"> Estándar</label>
  <label><input type="radio" name="speed" value="express"> Expreso</label>
</fieldset>

<label for="message">Mensaje</label>
<textarea id="message" name="message" rows="4"></textarea>

Los botones también toman un type. type="submit" envía el formulario (el predeterminado para un botón dentro de un formulario), type="reset" borra cada campo de vuelta a su valor inicial, y type="button" no hace nada por sí solo y está allí para que JavaScript se enganche.

Cada tipo de control lleva comportamiento que vale la pena conocer antes de que lo envíes. Los botones de radio se agrupan por un name compartido: solo un radio en un grupo puede seleccionarse a la vez, y esa agrupación es lo que los hace mutuamente excluyentes, así que un name faltante o mal emparejado silenciosamente rompe el grupo en interruptores independientes.

html
<fieldset>
  <legend>Velocidad de entrega</legend>
  <label><input type="radio" name="speed" value="standard" checked> Estándar</label>
  <label><input type="radio" name="speed" value="express"> Expreso</label>
</fieldset>

Un <fieldset> y <legend> no son solo visuales. El <legend> es anunciado por lectores de pantalla como contexto para cada control en el conjunto, así que un radio dentro del fieldset "Velocidad de entrega" se lee como "Velocidad de entrega, Estándar", que es la diferencia entre un formulario comprensible y una lista de opciones sin amarres. Dos notas más de producción. Una casilla de verificación solo envía su valor cuando está marcada; un cuadro sin marcar está ausente del envío completamente, así que el servidor ve nada en lugar de un false, que moldeа cómo lees los datos del otro lado. Y type="submit" es el tipo predeterminado para un <button> dentro de un formulario, así que un <button> desnudo que tenías la intención de usar como disparador de JavaScript enviará el formulario y recargará la página a menos que establezcas type="button". Ese comportamiento predeterminado atrapa a la gente constantemente.

JunoOtros controles Un formulario puede preguntar de más de una forma: un cuadro de verificación para sí-o-no, un desplegable para elegir una cosa de una lista. Una casilla de verificación es <input type="checkbox">, y un desplegable es un <select> que contiene opciones <option>. No necesitas memorizarlos; el formulario tiene más que cuadros simples cuando una pregunta lo necesita.
JunoOtros controles El type del input lo remodela: email, number, date, password, checkbox, radio, cada uno con un teclado o selector apropiado. Recurre a <textarea> para texto largo, <select> para un desplegable, y un <fieldset> con una <legend> para agrupar campos relacionados. Observa los tipos de botón: submit es el predeterminado dentro de un formulario.
JunoOtros controles Los radios se agrupan por un name compartido, y una <legend> da a cada control en el fieldset contexto hablado, así que es estructura, no decoración. Dos trampas: una casilla de verificación sin marcar no envía nada en absoluto, no un false, y un <button> desnudo predetermina a type="submit", así que recargará la página a menos que establezcas type="button".

Cómo se nombran y se envían los datos del formulario

Cuando se envía un formulario, cada respuesta necesita una etiqueta para que quien la reciba sepa de qué cuadro vino. Esa etiqueta es el name del input. Lo estableces una vez, y viaja con el valor.

html
<label for="city">Ciudad</label>
<input id="city" name="city">

Si el visitante escribe "Buenos Aires" en ese cuadro, el formulario envía el par "city es Buenos Aires". El name es cómo el lado receptor separa una respuesta de otra. Un input sin name se deja fuera del envío completamente, así que este pequeño atributo es el que realmente hace que los datos aparezcan.

Los datos del formulario se envían como un conjunto de pares nombre/valor: el name de cada control se convierte en la clave y lo que el visitante ingresó se convierte en el valor. Solo los controles con un name se incluyen, así que un name es lo que convierte un control en datos enviados.

html
<form action="/search" method="get">
  <label for="q">Búsqueda</label>
  <input id="q" name="q" type="search">
  <label for="sort">Ordenar por</label>
  <select id="sort" name="sort">
    <option value="recent">Más reciente</option>
    <option value="top">Mejor valorado</option>
  </select>
  <button type="submit">Buscar</button>
</form>

El atributo method elige cómo viajen esos pares. method="get" los agrega a la URL como una cadena de consulta (/search?q=botas&sort=recent), que se adapta bien a búsquedas y filtros que podrías marcar o compartir. method="post" los pone en el cuerpo de la solicitud fuera de vista, que se adapta a cualquier cosa que cambie datos o no deba estar en una URL, como una contraseña o un pago.

Cada envío es un conjunto de pares nombre/valor, y tres detalles deciden cómo se codifican y se envían.

El method es el primero. get serializa los pares en la URL como una cadena de consulta, el texto ?key=value&key=value después de la dirección. Eso hace que la solicitud sea repetible y marcable, y significa que los valores son visibles en la URL, en el historial del navegador, y en los registros del servidor, así que get es para lecturas (búsquedas, filtros) y nunca para secretos. post lleva los pares en el cuerpo de la solicitud en su lugar, fuera de la URL, que es la opción para cualquier cosa que cambie estado o sea sensible.

El enctype es el segundo: la codificación que dice cómo se formatea el cuerpo. El predeterminado, application/x-www-form-urlencoded, empaqueta los pares en una cadena key=value&... única, que está bien para texto. Para enviar un archivo elegido debes cambiar a enctype="multipart/form-data", el formato que puede llevar bytes de archivo junto a campos de texto; un input de archivo no se cargará correctamente sin él.

html
<form action="/upload" method="post" enctype="multipart/form-data">
  <label for="avatar">Foto de perfil</label>
  <input id="avatar" name="avatar" type="file">
  <button type="submit">Cargar</button>
</form>

El tercero es autocomplete, y es donde la nomenclatura devuelve UX y accesibilidad. Un token autocomplete le dice al navegador lo que significa un campo en términos estándar, así que puede ofrecer el valor guardado correcto: autocomplete="email", autocomplete="name", autocomplete="current-password", autocomplete="street-address". Estos tokens son un vocabulario fijo, no texto libre, y acertarlos permite que un navegador o un gestor de contraseñas complete un formulario en un toque, que importa más para las personas que escriben en un teléfono o que usan tecnología de asistencia.

html
<label for="email">Correo</label>
<input id="email" name="email" type="email" autocomplete="email">

Mantener honestos los cheques integrados es un trabajo separado, cubierto en el capítulo de validación de formularios; esta sección trata sobre cómo se moldean y se envían los datos una vez que son válidos.

JunoCómo se nombran y se envían los datos del formulario El name de cada input es la etiqueta en su respuesta, así que el receptor sabe que un valor vino del cuadro de ciudad y no del de correo. Establece name, y el valor del cuadro se envía como un par etiquetado. Olvídalo, y ese campo se deja silenciosamente fuera, que es lo que confunde a mucha gente la primera vez que un formulario no envía nada.
JunoCómo se nombran y se envían los datos del formulario Los datos enviados son pares nombre/valor, y solo los controles con un name se incluyen. Elige el method para que coincida con el trabajo: get pone valores en la URL para búsquedas y filtros que podrías marcar, post los oculta en el cuerpo para cualquier cosa que cambie datos u tenga un secreto. Las contraseñas en una URL es el error que nunca debes cometer.
JunoCómo se nombran y se envían los datos del formularioget escribe los pares en la URL, así que es para lecturas y nunca para secretos; post los lleva en el cuerpo. Cambia enctype a multipart/form-data o un input de archivo no se cargará. Y dedica el esfuerzo a tokens autocomplete como email y current-password: son un vocabulario fijo, y acertarlos permite que un teléfono o un gestor de contraseñas complete el formulario en un toque.