<input>
Formularios
Void element de formulario cuyo comportamiento y apariencia cambian completamente según el valor del atributo type: desde un campo de texto hasta un selector de color, fecha, archivo o un checkbox. Es el control de formulario más versátil del HTML.
<input> es el control de formulario más versátil del HTML y, por esa misma razón, el más complejo. A diferencia de casi todos los elementos HTML —que tienen un propósito fijo— <input> cambia completamente su comportamiento, su apariencia y las restricciones de validación que acepta según el valor de su atributo type. Un <input type="text"> es un campo de texto libre; un <input type="checkbox"> es una casilla de verificación; un <input type="color"> abre un selector de color. Son visualmente distintos, se usan de manera diferente y generan valores con formatos distintos, pero todos comparten el mismo elemento HTML.
<input> es un void element: no tiene etiqueta de cierre ni contenido. Su “valor” no vive entre etiquetas como en <textarea> — vive en el atributo value, o en el estado interno del control cuando el usuario interactúa con él. Para que el valor del control viaje al servidor al enviar el formulario, el <input> debe tener un atributo name que actúa como clave en el par nombre=valor de la petición HTTP.
La validación nativa del navegador —que funciona sin JavaScript— también vive en atributos de <input>: required, minlength, maxlength, min, max, pattern, type. Cada uno agrega una restricción que el navegador verifica antes de enviar el formulario. Esta combinación de tipos y atributos de validación hace de <input> el elemento con mayor superficie de atributos de todo HTML.
Cómo funciona
<input> es un replaced element: el navegador lo reemplaza por un widget nativo del sistema operativo cuyo aspecto y comportamiento están definidos por el navegador, no por el HTML. Esto significa que un <input type="date"> se ve diferente en Chrome, Firefox y Safari, y distinto aún en Android vs iOS. El CSS puede ajustar tamaño, color de borde y algunos aspectos, pero el widget interno es del navegador.
Al enviarse el formulario padre, el navegador toma el valor actual del control (lo que el usuario escribió o seleccionó) y lo envía como el valor del par name=valor. Para tipos booleanos como checkbox y radio, el valor enviado es el del atributo value cuando está marcado; si no está marcado, el control directamente no se incluye en el envío.
Modelo de contenido
<input> es un void element: sin etiqueta de cierre, sin contenido. Display por defecto: inline-block. Es un elemento interactivo y debe estar asociado a un <label> para ser accesible.
Sintaxis
<!-- Void element: sin etiqueta de cierre -->
<input type="text" id="nombre" name="nombre" placeholder="Tu nombre">
<input type="email" id="correo" name="correo" required>
<input type="checkbox" id="terminos" name="terminos" value="aceptado">
Tipos (type)
El atributo type es el más importante de <input>. Su valor por defecto es text.
type="text" — texto libre
El tipo más básico. Campo de texto de una sola línea, sin restricción de formato. Acepta cualquier carácter.
<input type="text" id="nombre" name="nombre" placeholder="Tu nombre completo">
Cuándo usarlo: nombres, apellidos, títulos, cualquier dato textual que no tenga un tipo más específico.
type="email" — dirección de correo
El navegador valida que el valor tenga el formato básico de un email (texto@dominio.algo). En dispositivos móviles muestra un teclado optimizado con @ visible.
<input type="email" id="correo" name="correo" required>
Gotcha: la validación del navegador es básica (comprueba el formato, no que el email exista). El backend siempre debe revalidar.
type="password" — contraseña
Oculta los caracteres mientras el usuario escribe (los muestra como puntos o asteriscos). El valor real sí se envía al servidor.
<input type="password" id="clave" name="clave" minlength="8" required>
Importante: type="password" solo oculta visualmente. Para seguridad real, el formulario debe usar HTTPS y el backend debe hashear la contraseña antes de guardarla.
type="number" — número
Acepta solo valores numéricos. Muestra flechas de incremento/decremento (spinners). Acepta los atributos min, max y step.
<input type="number" id="edad" name="edad" min="18" max="99" step="1">
Gotcha: en algunos navegadores, type="number" con step no acepta decimales. Para valores decimales, especificá step="0.01" o step="any".
type="tel" — número de teléfono
No valida el formato (los formatos telefónicos varían demasiado por país). En móviles muestra el teclado numérico. El formato se valida con pattern.
<input type="tel" id="telefono" name="telefono" pattern="[0-9+\-\s()]{7,20}">
type="url" — URL
Valida que el valor comience con un protocolo (http://, https://, etc.). Útil para campos de sitio web.
<input type="url" id="sitio" name="sitio" placeholder="https://tusitio.com">
type="search" — búsqueda
Semánticamente igual a text, pero con estilo visual diferente en algunos navegadores (botón de borrar la búsqueda). Comunica al navegador la intención semántica del campo.
<input type="search" id="q" name="q" placeholder="Buscar...">
type="checkbox" — casilla de verificación
Crea una casilla que el usuario puede marcar o desmarcar. Cada checkbox es independiente. Cuando está marcado, envía el valor del atributo value; cuando no está marcado, el control no se incluye en el envío.
<input type="checkbox" id="terminos" name="terminos" value="aceptado">
<label for="terminos">Acepto los términos</label>
Candidato a página propia a futuro: el checkbox tiene su modelo de interacción específico (:checked, valor booleano vs value, grupos con name vs independientes), que justificaría una entrada propia si se profundiza más allá del uso básico.
type="radio" — botón de opción
Los radio buttons que comparten el mismo name forman un grupo mutuamente excluyente: solo uno puede estar seleccionado a la vez. Requieren que cada opción tenga su propio id y value.
<fieldset>
<legend>Método de pago</legend>
<input type="radio" id="credito" name="pago" value="credito">
<label for="credito">Tarjeta de crédito</label>
<input type="radio" id="debito" name="pago" value="debito">
<label for="debito">Tarjeta de débito</label>
</fieldset>
Gotcha: radio buttons con name distintos son independientes y no se excluyen mutuamente. El error más frecuente es olvidar que el name debe ser el mismo en todos los radios del grupo.
Candidato a página propia a futuro: junto con type="checkbox", el modelo radio tiene suficiente superficie (grupos, :checked, fieldset/legend para accesibilidad) para justificar su propia entrada.
type="file" — selector de archivo
Abre el selector de archivos del sistema operativo. El formulario que lo contiene debe tener enctype="multipart/form-data" y method="post".
<form method="post" enctype="multipart/form-data">
<input type="file" id="foto" name="foto" accept="image/*">
</form>
El atributo accept filtra los tipos de archivo que el selector muestra (no es seguridad — el filtro es del OS, el backend valida). multiple permite seleccionar varios archivos.
Candidato a página propia a futuro: type="file" tiene modelo propio (el archivo no va en value, requiere enctype, accept, multiple, consideraciones de seguridad del backend) que justifica una entrada separada.
type="date" / type="time" / type="datetime-local" — fecha y hora
Generan controles nativos del navegador para seleccionar fecha y hora. El valor se envía en formato ISO (2026-06-17). Acepta min, max y step.
<input type="date" id="nacimiento" name="nacimiento" min="1920-01-01" max="2010-12-31">
<input type="time" id="hora" name="hora">
<input type="datetime-local" id="reunion" name="reunion">
Gotcha: el aspecto del picker varía significativamente entre navegadores. En 2026 todos los navegadores modernos los soportan bien, pero para UX consistente muchas apps usan librerías JS de datepicker.
type="range" — deslizador
Renderiza un slider. El usuario arrastra para seleccionar un valor numérico. Acepta min, max y step. No muestra el valor actual por defecto — combinarlo con <output> para mostrarlo.
<input type="range" id="volumen" name="volumen" min="0" max="100" step="5" value="50">
type="color" — selector de color
Abre un picker de color. El valor se envía en formato hexadecimal (#rrggbb).
<input type="color" id="fondo" name="fondo" value="#0d9488">
type="hidden" — campo oculto
No se renderiza al usuario pero sí se incluye en el envío. Útil para pasar datos internos (tokens CSRF, IDs de registro, paso del formulario multipagina).
<input type="hidden" name="csrf_token" value="abc123xyz">
Importante: type="hidden" es invisible en la UI pero visible en el código fuente. No es un mecanismo de seguridad para datos sensibles.
type="submit" — botón de envío (inline)
Crea un botón de envío como void element. La alternativa preferida en HTML moderno es <button type="submit">, que permite contenido HTML dentro. Ver la entrada de <button>.
<input type="submit" value="Enviar formulario">
Atributos comunes
name — clave de envío
La clave del par nombre=valor en la petición HTTP. Sin name, el control no se incluye en el envío. Obligatorio en todo control que deba enviar datos.
Default: no presente.
value — valor inicial
El valor con que nace el campo. Para text/email/etc., es el texto prefijado. Para checkbox/radio, es el valor enviado cuando está marcado.
placeholder — texto de ayuda contextual
Texto gris que aparece cuando el campo está vacío y desaparece al escribir. Describe el formato esperado, no el label del campo.
<input type="email" placeholder="tu@ejemplo.com">
Gotcha: placeholder no reemplaza al <label>. El placeholder desaparece al escribir; el lector de pantalla puede no anunciarlo al entrar al campo. Usá siempre un <label> visible además del placeholder.
required — campo obligatorio
Atributo booleano. El formulario no se envía si el campo está vacío.
<input type="text" name="nombre" required>
CSS: :required para estilizar campos obligatorios; :optional para los no obligatorios.
disabled — campo deshabilitado
Atributo booleano. El control no es interactivo, no recibe foco, no puede ser editado, y su valor no se envía al servidor.
<input type="text" name="codigo" value="PRE-001" disabled>
CSS: :disabled para aplicar estilos al estado deshabilitado.
Diferencia con readonly: un campo disabled no se envía; un campo readonly sí se envía pero no puede editarse.
readonly — campo de solo lectura
El usuario puede ver y copiar el valor pero no modificarlo. A diferencia de disabled, el valor sí se incluye en el envío.
<input type="text" name="usuario" value="ana_garcia" readonly>
CSS: :read-only / :read-write.
autocomplete — autocompletar
Controla si el navegador puede sugerir valores guardados. Acepta on, off, y valores semánticos específicos (name, email, tel, new-password, etc.).
<!-- Sugiere contraseñas guardadas -->
<input type="password" name="clave" autocomplete="current-password">
<!-- Para nuevas contraseñas — impide que el gestor sugiera la actual -->
<input type="password" name="nueva-clave" autocomplete="new-password">
min / max / step — rango numérico
Para type="number", type="range", y tipos de fecha/hora. Definen el rango válido y el incremento.
<input type="number" min="0" max="100" step="5">
CSS: :in-range / :out-of-range.
pattern — expresión regular de validación
El valor debe coincidir con la regex. Aplica a campos de texto.
<!-- Solo letras y espacios -->
<input type="text" pattern="[A-Za-záéíóúÁÉÍÓÚñÑ\s]+" title="Solo letras">
El atributo title en combinación con pattern mejora el mensaje de error que muestra el navegador.
maxlength / minlength — longitud de texto
Restricciones de cantidad de caracteres para campos de texto.
<input type="text" name="usuario" minlength="3" maxlength="20">
checked — marcado por defecto
Para checkbox y radio. Marca el control como seleccionado al cargar la página.
<input type="checkbox" name="newsletter" value="si" checked>
<input type="radio" name="pais" value="argentina" checked>
multiple — múltiple selección
Para type="email" (permite ingresar varias direcciones separadas por coma) y type="file" (permite seleccionar varios archivos).
<input type="file" name="fotos" multiple accept="image/*">
accept — tipos de archivo aceptados
Solo para type="file". Filtra los archivos que muestra el selector. Acepta tipos MIME (image/*, application/pdf) o extensiones (.jpg,.png).
<input type="file" name="cv" accept=".pdf,.doc,.docx">
Estados e interacción
<input> tiene un conjunto rico de pseudoclases CSS para reflejar su estado:
| Pseudoclase | Cuándo activa |
|---|---|
:focus | El campo tiene el foco (teclado o clic) |
:disabled | El control tiene el atributo disabled |
:checked | Checkbox o radio está marcado |
:required | El control tiene el atributo required |
:optional | El control NO tiene required |
:valid | El valor cumple todas las restricciones de validación |
:invalid | El valor viola al menos una restricción |
:placeholder-shown | El placeholder es visible (campo vacío) |
:in-range / :out-of-range | Para number y range: dentro/fuera del rango |
:read-only / :read-write | Control con/sin el atributo readonly |
input:focus {
outline: 2px solid #1d4ed8;
outline-offset: 2px;
}
input:invalid {
border-color: #dc2626;
}
input:valid {
border-color: #16a34a;
}
input:disabled {
opacity: 0.5;
cursor: not-allowed;
}
Gotcha con :invalid: al cargar la página, un campo required vacío ya es :invalid. Esto puede mostrar el estilo de error antes de que el usuario haya interactuado con él. Para evitar el “formulario rojo antes de empezar”, usá :user-invalid (bien soportado en 2026) o combiná con :not(:placeholder-shown):invalid.
Accesibilidad
Todo <input> visible debe tener un <label> asociado. Las dos formas:
Con for/id (recomendada): el for del label apunta al id del input.
<label for="nombre">Nombre</label>
<input type="text" id="nombre" name="nombre">
Forma envolvente: el input dentro del label crea la vinculación implícita.
<label>Nombre <input type="text" name="nombre"></label>
Sin label, el lector de pantalla anuncia el campo como “campo de texto — sin nombre”. El placeholder no reemplaza al label: desaparece al escribir y puede no ser anunciado por todos los lectores de pantalla al entrar al campo.
Para grupos de radio buttons y checkboxes relacionados, usar <fieldset> con <legend> da el contexto del grupo a los lectores de pantalla.
Cuándo usar qué tipo
| Necesidad | type recomendado |
|---|---|
| Texto libre (nombre, título) | text |
| Dirección de email | email |
| Contraseña | password |
| Número entero o decimal | number |
| Fecha | date |
| Hora | time |
| Teléfono | tel |
| URL | url |
| Búsqueda | search |
| Opción marcable independiente | checkbox |
| Una opción de un grupo exclusivo | radio |
| Archivo del sistema | file |
| Valor en rango (slider) | range |
| Color | color |
| Dato oculto | hidden |
Notas, gotchas e interacción
namees la clave de envío,ides la clave del DOM. Son atributos distintos con propósitos distintos. Elfordel<label>apunta alid; el servidor recibe elname. Que tengan el mismo valor es convención, no requisito técnico.- Checkbox desmarcado no se envía. Si ningún checkbox de un grupo está marcado, el servidor no recibe esa clave en absoluto. Para saber que el usuario no marcó nada, se suele acompañar con un
<input type="hidden" name="misma-clave" value="no">. type="number"no es para todos los “números”. Números de teléfono, códigos postales y tarjetas de crédito tienen formato específico y deben usartype="tel"otype="text"conpattern, notype="number".placeholder≠label. El placeholder es ayuda de formato, no el nombre del campo. Siempre hay un label visible.
Vigente / legacy
<input> está completamente vigente. Los atributos align y border (presentación inline) son legacy desde HTML5. El tipo type="image" (input de imagen como botón de submit) está en desuso para efectos prácticos — preferí un <button> con una <img> dentro. Los tipos no reconocidos por el navegador caen silenciosamente a type="text", lo que puede causar comportamiento inesperado al actualizar navegadores.