acerca de HTML

Referencia de etiquetas

Etiqueta input en HTML: tipos, atributos y validación

La etiqueta <input> crea controles de formulario cuyo comportamiento depende del atributo type. Sirve para recoger un correo, una contraseña, una cantidad, una elección o un archivo, entre otros datos. Úsala cuando necesites un control de entrada de una sola línea o alguno de sus selectores nativos; elegir el tipo correcto ayuda al navegador a ofrecer la interacción y las comprobaciones adecuadas.

Ejemplo mínimo: pedir un correo

<label for="correo">Correo electrónico</label>
<input id="correo" name="correo" type="email" autocomplete="email" required>

Verás una etiqueta visible y un campo. for="correo" lo asocia con el id del control; pulsar la etiqueta lleva el foco al campo. autocomplete="email" indica qué dato puede sugerir el navegador, sin garantizar que tenga una dirección guardada. required exige un valor y type="email" comprueba una sintaxis básica al validar el formulario: no demuestra que el correo exista ni que pertenezca a quien lo escribió. Consulta la referencia de email.

Para probarlo, pega el fragmento dentro del <body> de un documento HTML con doctype, idioma español y codificación UTF-8. El campo funciona fuera de un formulario, pero este fragmento no envía datos. Puedes comprobar su validez con document.getElementById("correo").reportValidity() en la consola. El caso práctico incluye un documento completo y un botón para iniciar la validación.

Sintaxis y contexto válido

<input> es un elemento vacío: no contiene texto ni otros elementos y no tiene etiqueta de cierre. Escribe <input type="text">, sin </input>. Puede aparecer donde se admite contenido de frase, por ejemplo dentro de un párrafo del formulario. No introduzcas un control interactivo dentro de otro botón o de un enlace.

Si omites type o escribes un valor desconocido como type="correo", el tipo efectivo es text. Eso no conserva la validación de email. Las reglas están en el modelo de contenido y tipos de input del estándar.

Habitualmente el control pertenece al <form> que lo contiene. También puede asociarse desde fuera con form="id-del-formulario". Para enviar un campo común necesitas name; para darle nombre accesible, utiliza <label>. hidden no admite etiqueta visible ni foco; los botones se nombran con su texto de value, y image necesita alt.

Tipos de input: cuál elegir

typeCuándo usarlo y qué ofrece
textTexto de una línea, como un nombre o código postal. Tipo predeterminado.
searchConsulta de búsqueda; puede ofrecer un botón para borrar el texto.
emailDirección de correo; comprueba formato y puede adaptar el teclado móvil.
urlURL absoluta; comprueba formato, no que el recurso exista.
telTeléfono; puede ofrecer un teclado apropiado, pero no impone un formato internacional.
passwordTexto oculto visualmente; no cifra el valor.
numberCantidad numérica, con límites y pasos; puede mostrar botones de incremento.
dateFecha con año, mes y día; su selector y presentación dependen del navegador.
timeHora sin fecha ni zona horaria.
datetime-localFecha y hora locales sin zona horaria.
monthAño y mes; comprueba la compatibilidad del selector en tus navegadores objetivo.
weekAño y semana ISO; comprueba compatibilidad y explica el formato esperado.
checkboxCasilla para una decisión independiente o varias selecciones.
radioUna opción de un grupo con el mismo name.
rangeDeslizador para una cantidad aproximada; tiene un valor aunque no se toque.
colorSelección de color mediante la interfaz disponible.
fileElección de archivos del dispositivo, sin cargarlos automáticamente.
hiddenDato asociado al formulario sin interfaz visible; no es un secreto.
submitBotón que inicia el envío y la validación del formulario.
resetBotón que restablece valores iniciales; puede borrar cambios involuntariamente.
buttonBotón sin acción predeterminada; necesita una acción programada.
imageBotón de envío con imagen; requiere src y alt y aporta coordenadas.

El soporte del elemento no garantiza la misma interfaz para todos los tipos. Cambian los calendarios, selectores de archivos y teclados según navegador y sistema operativo. Si un tipo no está implementado, puede volver a un campo de texto: ofrece instrucciones y valida los datos en el servidor. Revisa las compatibilidades de input, month y week.

number representa cantidades con las que tiene sentido calcular, como el número de plazas. Un teléfono o código postal es un identificador: utiliza tel o text, respectivamente, para conservar ceros iniciales y admitir sus formatos. inputmode="numeric" puede sugerir un teclado numérico para un código postal sin convertirlo en cantidad. Consulta number en MDN.

Atributos según el tipo de control

Identificación, valor y autocompletado

¿id y name tienen la misma función? No. id identifica el elemento de forma única y permite asociar una etiqueta, estilos o scripts. name define la clave de los datos enviados: id="correo" name="email" produce la clave email. Quitar name deja visible el campo, pero lo excluye de los datos del formulario.

En campos de texto, el atributo HTML value fija el valor inicial; la propiedad DOM .value refleja el valor actual. Después de escribir, ambos pueden diferir. En casillas y radios, value establece el dato de la opción, mientras que checked fija su selección inicial y .checked indica la selección actual. Sin value, una casilla o radio marcado aporta on. Consulta checkbox y radio.

autocomplete describe el dato esperado en los tipos compatibles: name, email, tel, current-password o new-password, por ejemplo. No uses el mismo token para datos distintos; off tampoco garantiza que un gestor de contraseñas deje de actuar. Revisa los tokens de autocomplete.

Required, disabled y readonly

AtributoEdición, foco, validación y datos
requiredExige completar un control compatible antes del envío. En una casilla exige marcar esa casilla; en un grupo de radios exige elegir una opción. No se aplica a hidden, range, color ni botones.
disabledImpide usar el control: queda fuera del recorrido de foco, de la validación y de los datos enviados. Puede aplicarse a cualquier tipo de input.
readonlyImpide editar campos textuales, numéricos y temporales compatibles. Conserva el foco y el valor en los datos enviados, pero excluye el control de la validación. No sirve para casillas, radios, archivos, range, color ni botones.

¿disabled y readonly son iguales? No: el primero excluye el dato del envío; el segundo conserva el valor de un control compatible. Ninguno protege frente a cambios hechos mediante herramientas de desarrollo o peticiones construidas aparte. El servidor debe verificar los datos.

Los tres son atributos booleanos: cuenta su presencia. disabled="false" sigue deshabilitando el control; para habilitarlo elimina el atributo. Combinar required con readonly no sirve para exigir un dato editable y no es una combinación válida de autoría. Consulta required, disabled y readonly.

Límites, patrones, archivos y sugerencias

AtributosDónde y cómo utilizarlos
min, max, stepPara number, range y tipos temporales. Definen límites y valores admitidos respecto a una base; no longitudes del texto. En number, el paso predeterminado es 1: usa, por ejemplo, step="0.5" para medios puntos.
minlength, maxlengthPara text, search, email, url, tel y password. Limitan la longitud en unidades UTF-16; minlength no convierte un campo opcional en obligatorio.
patternPara esos mismos seis tipos textuales. Expresión regular que debe coincidir con todo el valor no vacío; no se aplica a number.
multiplePermite varios archivos en file o correos separados por comas en email. No convierte cualquier campo en una lista.
acceptEn file, sugiere extensiones o tipos MIME, por ejemplo .pdf,application/pdf. No valida el contenido del archivo.
listAsocia un <datalist> mediante su id para sugerir valores en tipos compatibles. No restringe la entrada a esas opciones; no se aplica a hidden, password, casillas, radios, archivos ni botones.

Los límites se detallan en min, max, step, minlength y maxlength. Las selecciones múltiples y los archivos tienen sus propias reglas: multiple y file.

El pattern vigente se compila con la bandera JavaScript v, sin barras delimitadoras. Por ejemplo, pattern="[A-Za-z0-9]{3,16}" admite entre 3 y 16 letras ASCII o dígitos. Explica el formato en texto visible y asócialo con aria-describedby; no dependas solo de title. Un patrón inválido no impone la restricción. Consulta la sintaxis actual de pattern.

id, class, lang e inputmode son globales; los atributos anteriores dependen del control. width en una regla CSS es presentación, .value es una propiedad DOM y input es un evento: no son atributos HTML intercambiables.

Caso práctico: inscripción y FormData sin envío

Guarda este documento como prueba-input.html en UTF-8 y ábrelo en el navegador. Utiliza un correo y una contraseña ficticios. No requiere servidor ni archivos externos; seleccionar un PDF propio es opcional. El script muestra los datos preparados por FormData, oculta la contraseña en la salida y evita el envío. No crea una cuenta ni guarda la inscripción.

<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Inscripción local con input</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 1rem; }
    #input-inscripcion fieldset { min-width: 0; }
    #input-inscripcion input { box-sizing: border-box; max-width: 100%; }
    #input-datos { white-space: pre-wrap; overflow-wrap: anywhere; }
    #input-inscripcion .error { display: block; }
  </style>
</head>
<body>
  <h1>Inscripción de prueba al taller</h1>
  <p>Correo y contraseña son obligatorios. Los demás datos son opcionales.</p>
  <form id="input-inscripcion" method="post" enctype="multipart/form-data">
    <fieldset id="input-campos" disabled>
      <legend>Datos de prueba</legend>
      <p>
        <label for="input-correo">Correo electrónico (obligatorio)</label>
        <input id="input-correo" name="email" type="email"
               autocomplete="email" required
               aria-describedby="input-correo-error">
        <span id="input-correo-error" class="error"></span>
      </p>
      <p>
        <label for="input-clave">Contraseña ficticia (obligatoria)</label>
        <input id="input-clave" name="clave" type="password"
               autocomplete="new-password" minlength="8" required
               aria-describedby="input-clave-ayuda input-clave-error">
        <small id="input-clave-ayuda">Al menos 8 caracteres para esta prueba.</small>
        <span id="input-clave-error" class="error"></span>
      </p>
      <fieldset>
        <legend>Modalidad (opcional, una sola elección)</legend>
        <input id="input-presencial" name="modalidad" type="radio" value="presencial">
        <label for="input-presencial">Presencial</label>
        <input id="input-online" name="modalidad" type="radio" value="online">
        <label for="input-online">En línea</label>
      </fieldset>
      <p>
        <label for="input-archivo">Documento PDF (opcional)</label>
        <input id="input-archivo" name="documento" type="file"
               accept=".pdf,application/pdf" aria-describedby="input-archivo-ayuda">
        <small id="input-archivo-ayuda">El selector sugiere PDF; no valida su contenido.</small>
      </p>
      <p>
        <input id="input-novedades" name="novedades" type="checkbox" value="si">
        <label for="input-novedades">Quiero novedades (opcional)</label>
      </p>
      <button type="submit">Ver datos de prueba</button>
    </fieldset>
  </form>
  <p id="input-estado" role="status">Ningún dato se ha enviado ni guardado.</p>
  <pre id="input-datos" aria-label="Datos preparados"></pre>
  <noscript>
    <p>La vista de datos necesita JavaScript. Los controles quedan deshabilitados;
       puedes leer el código y los resultados esperados de la guía.</p>
  </noscript>
  <script>
    (() => {
      const formulario = document.getElementById("input-inscripcion");
      const campos = document.getElementById("input-campos");
      const salida = document.getElementById("input-datos");
      const estado = document.getElementById("input-estado");
      if (!("FormData" in window)) {
        estado.textContent = "Este navegador no dispone de FormData.";
        return;
      }
      formulario.addEventListener("invalid", (evento) => {
        const control = evento.target;
        const error = document.getElementById(control.id + "-error");
        if (error) {
          error.textContent = control.validationMessage;
          control.setAttribute("aria-invalid", "true");
        }
      }, true);
      formulario.addEventListener("input", (evento) => {
        const control = evento.target;
        const error = document.getElementById(control.id + "-error");
        if (error) {
          error.textContent = "";
          control.removeAttribute("aria-invalid");
        }
        salida.textContent = "";
        estado.textContent = "Datos modificados; vuelve a comprobarlos.";
      });
      formulario.addEventListener("submit", (evento) => {
        evento.preventDefault();
        const datos = new FormData(formulario);
        const lineas = Array.from(datos, ([nombre, valor]) => {
          if (nombre === "clave") return "clave = [oculta en esta vista]";
          if (valor instanceof File) {
            return nombre + " = " + (valor.name
              ? valor.name + " (" + valor.size + " bytes)" : "[sin archivo]");
          }
          return nombre + " = " + valor;
        });
        for (const nombre of ["modalidad", "novedades"]) {
          if (!datos.has(nombre)) lineas.push(nombre + " = [clave ausente]");
        }
        salida.textContent = lineas.join("\n");
        estado.textContent = "Datos mostrados; no se han enviado ni guardado.";
      });
      campos.disabled = false;
    })();
  </script>
</body>
</html>

Prueba en este orden:

  1. Activa el botón con los campos vacíos: el navegador bloquea el envío, enfoca el primer campo inválido y aparecen errores vinculados al correo y a la contraseña.
  2. Escribe ana@example.test y una clave ficticia corta; vuelve a comprobar. La longitud insuficiente impide continuar. Corrige con prueba123.
  3. Deja radios, archivo y casilla sin seleccionar. La salida mostrará el correo, la clave oculta, documento = [sin archivo] y las claves ausentes de modalidad y novedades. Estas últimas líneas las añade el script para explicarlo: no son entradas de FormData.
  4. Usa Tab para recorrer controles, flechas para cambiar entre radios y Espacio para marcar la casilla. Selecciona un PDF y vuelve a activar el botón con Enter. Aparecerán modalidad = presencial u online, novedades = si y el nombre y tamaño del archivo. El foco permanece en el botón; editar un dato borra la salida anterior.
  5. Deshabilita JavaScript y recarga: verás el aviso y los controles seguirán deshabilitados. Así esta demostración local evita un envío accidental a la página actual.

Los radios comparten name="modalidad" y formulario para permitir una sola elección; si ninguno está marcado, no hay entrada. Una casilla desmarcada tampoco envía false. En cambio, un archivo sin selección produce una entrada con un File vacío y nombre vacío. FormData reúne estos datos, pero no inicia una petición por sí mismo; consulta su API.

Prueba a retirar name del correo: desaparece de los datos aunque siga validándose. Cambiar su tipo a text elimina la comprobación de formato. Retirar el <input> elimina el control, su dato y sus restricciones; conservar solo el <label> no recoge información.

Para una inscripción real, implementa un destino POST y configura action; el sitio no proporciona ese servicio. Conserva enctype="multipart/form-data" para el envío nativo de archivos, retira el script local y el disabled inicial y prepara una respuesta del servidor que funcione también sin JavaScript. Comprueba allí los valores, las opciones permitidas, el tamaño y el contenido del archivo. accept solo guía al selector. password solo oculta la representación visual: usa HTTPS y almacenamiento adecuado de contraseñas; ocultar también la salida de esta demo no cambia el valor recogido. Consulta password.

Fechas, accesibilidad y errores frecuentes

En date, la presentación puede seguir el idioma del navegador, pero el valor de una fecha habitual como el 3 de octubre de 2026 es 2026-10-03. No incluye hora ni zona. En datetime-local, 2026-10-03T18:00 tampoco identifica un instante universal: si reservas una sesión entre distintas ciudades, recoge o acuerda una zona aparte y resuélvela en el servidor, considerando cambios de horario. No añadas una Z suponiendo que el dato ya representa UTC. Consulta date y datetime-local.

Un placeholder es una pista que desaparece al escribir; no sustituye al <label>. Mantén visibles los requisitos y errores, relaciónalos con aria-describedby y señala el estado inválido cuando se detecte. No comuniques un error solo con color ni elimines el indicador de foco. El ejemplo conserva la validación nativa y añade mensajes textuales; sus anuncios concretos dependen de la combinación de navegador y lector de pantalla.

Si el campo «no funciona», revisa primero el type efectivo; después, su name, su asociación con el formulario y si está deshabilitado. Si faltan opciones en los datos, comprueba qué casilla o radio está marcado. Si la validación no restringe lo esperado, comprueba que el atributo se aplique a ese tipo y que el patrón sea válido. Finalmente revisa el destino: crear controles no implementa un servidor.

Etiquetas relacionadas y fuentes

Usa <form> para coordinar envío y validación; <label> para nombrar un control; <datalist> para sugerencias editables y <button> cuando el botón necesite contenido más rico que el value de un input. Para texto de varias líneas utiliza <textarea>; para elegir de una lista de opciones cerrada, considera <select>.

Consulta técnica: 5 de octubre de 2026. El HTML Living Standard fija los tipos, el modelo y los atributos. Las referencias de MDN enlazadas en cada sección explican sus funciones y compatibilidad. Comprueba la interfaz concreta por teclado y en móvil en los navegadores que vayas a admitir; no basta con que el elemento exista.