Imágenes, Tablas y Formularios
Aprendé a mostrar imágenes, organizar datos en tablas y crear formularios para recolectar información del usuario.
Imágenes
La etiqueta <img> inserta una imagen en la página.
Es una etiqueta vacía — no tiene etiqueta de cierre — y requiere dos atributos obligatorios:
src (la ruta de la imagen) y alt (texto alternativo).
<!-- Imagen desde una URL externa -->
<img src="https://picsum.photos/300/200" alt="Foto aleatoria">
<!-- Imagen desde un archivo local -->
<img src="fotos/perfil.jpg" alt="Foto de perfil">
<!-- Con ancho y alto explícitos -->
<img src="logo.png" alt="Logo de la empresa" width="200" height="100">
<!-- Imagen con título (tooltip al pasar el mouse) -->
<img src="foto.jpg" alt="Paisaje" title="Tomada en Patagonia">
El atributo alt describe la imagen para lectores de pantalla (accesibilidad) y se muestra cuando la imagen no carga. Si la imagen es puramente decorativa, usá alt="" — vacío pero presente.
Rutas de archivos
<!-- Misma carpeta que el HTML -->
<img src="foto.jpg" alt="...">
<!-- Subcarpeta -->
<img src="imagenes/foto.jpg" alt="...">
<!-- Carpeta superior -->
<img src="../foto.jpg" alt="...">
<!-- Ruta absoluta desde la raíz del sitio -->
<img src="/assets/img/foto.jpg" alt="...">
Imagen como enlace
<!-- Envolver la imagen en un <a> la convierte en enlace -->
<a href="https://ejemplo.com">
<img src="banner.jpg" alt="Visitá nuestro sitio">
</a>
Figure y figcaption
Para imágenes con descripción, HTML5 ofrece las etiquetas semánticas
<figure> y <figcaption>:
<figure>
<img src="grafico.png" alt="Gráfico de ventas 2026">
<figcaption>Fig. 1 — Evolución de ventas durante 2026.</figcaption>
</figure>
JPG para fotos (compresión alta, sin transparencia). PNG para gráficos y logos (soporta transparencia). SVG para iconos e ilustraciones vectoriales. WebP para web moderno (mejor compresión que JPG/PNG).
Tablas
Las tablas organizan datos en filas y columnas. Están pensadas para datos tabulares — nunca para hacer layouts de página (eso es tarea del CSS).
Estructura básica
<table>
<thead> <!-- Encabezado de la tabla -->
<tr> <!-- Fila (table row) -->
<th>Nombre</th> <!-- Celda de encabezado (table header) -->
<th>Edad</th>
<th>Ciudad</th>
</tr>
</thead>
<tbody> <!-- Cuerpo de la tabla -->
<tr>
<td>Ana García</td> <!-- Celda de datos (table data) -->
<td>28</td>
<td>Córdoba</td>
</tr>
<tr>
<td>Carlos López</td>
<td>35</td>
<td>Buenos Aires</td>
</tr>
</tbody>
<tfoot> <!-- Pie de tabla (opcional) -->
<tr>
<td colspan="3">Total: 2 usuarios</td>
</tr>
</tfoot>
</table>
<table>
Contenedor de la tabla
<thead> / <tbody> / <tfoot>
Secciones semánticas
<tr>
Fila (table row)
<th> / <td>
Encabezado / Dato
colspan y rowspan — combinar celdas
<table>
<thead>
<tr>
<th colspan="2">Nombre Completo</th> <!-- ocupa 2 columnas -->
<th>País</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ana</td>
<td>García</td>
<td rowspan="2">Argentina</td> <!-- ocupa 2 filas -->
</tr>
<tr>
<td>Carlos</td>
<td>López</td>
<!-- la celda Argentina ya cubre esta fila -->
</tr>
</tbody>
</table>
Agregá scope="col" a los encabezados de columna y scope="row" a los de fila. Los lectores de pantalla lo usan para asociar celdas con sus encabezados.
Formularios
Los formularios permiten al usuario enviar datos. La etiqueta <form>
agrupa todos los campos. Los atributos action y method
definen a dónde y cómo se envían los datos.
<form action="/procesar.php" method="POST">
<!-- campos aquí -->
<button type="submit">Enviar</button>
</form>
| Atributo | Valor | Descripción |
|---|---|---|
action | URL | A dónde se envían los datos |
method | GET / POST | GET: datos en la URL. POST: datos ocultos en el cuerpo |
novalidate | — | Desactiva la validación nativa del navegador |
autocomplete | on / off | Activa o desactiva el autocompletado |
Campos de texto y contraseña
<!-- Texto simple -->
<label for="nombre">Nombre:</label>
<input type="text" id="nombre" name="nombre" placeholder="Escribí tu nombre">
<!-- Contraseña —oculta los caracteres -->
<label for="pass">Contraseña:</label>
<input type="password" id="pass" name="pass">
<!-- Email — valida el formato automáticamente -->
<input type="email" name="email" placeholder="usuario@ejemplo.com">
<!-- Número -->
<input type="number" name="edad" min="1" max="120">
<!-- Texto largo -->
<label for="bio">Descripción:</label>
<textarea id="bio" name="bio" rows="4" cols="40"></textarea>
El for del <label> debe coincidir con el id del campo. Esto hace que al hacer clic en el texto del label el foco vaya al campo — mejora la usabilidad y la accesibilidad.
Tipos de input más usados
<!-- Checkbox —puede seleccionar varios -->
<input type="checkbox" id="acepta" name="acepta" value="si">
<label for="acepta">Acepto los términos</label>
<!-- Radio —solo uno del grupo -->
<input type="radio" id="masculino" name="genero" value="M">
<label for="masculino">Masculino</label>
<input type="radio" id="femenino" name="genero" value="F">
<label for="femenino">Femenino</label>
<!-- Select —lista desplegable -->
<select name="pais">
<option value="">— Elegí un país —</option>
<option value="AR">Argentina</option>
<option value="BR">Brasil</option>
<option value="UY" selected>Uruguay</option>
</select>
<!-- Fecha -->
<input type="date" name="nacimiento">
<!-- Rango (slider) -->
<input type="range" name="volumen" min="0" max="100" value="50">
<!-- Color -->
<input type="color" name="favorito" value="#264DE4">
<!-- Archivo -->
<input type="file" name="foto" accept="image/*">
<!-- Oculto —no se muestra pero se envía -->
<input type="hidden" name="userId" value="42">
Probá el Ejemplo 3: Tipos de input
Atributos de validación
HTML5 incluye validación nativa sin JavaScript. El navegador verifica estos atributos antes de enviar el formulario:
<!-- required — campo obligatorio -->
<input type="text" name="nombre" required>
<!-- minlength / maxlength — longitud del texto -->
<input type="text" name="usuario" minlength="3" maxlength="20">
<!-- min / max — para números y fechas -->
<input type="number" name="edad" min="18" max="99">
<input type="date" name="fecha" min="2020-01-01" max="2026-12-31">
<!-- pattern — expresión regular -->
<input type="text" name="codigo" pattern="[A-Z]{3}-[0-9]{4}"
placeholder="Ej: ABC-1234"
title="Formato: 3 letras mayúsculas, guión, 4 números">
<!-- disabled — deshabilita el campo (no se envía) -->
<input type="text" name="id" value="42" disabled>
<!-- readonly — solo lectura (sí se envía) -->
<input type="text" name="codigo" value="A-001" readonly>
La validación HTML es solo una primera capa de comodidad para el usuario. Siempre validá también en el servidor — cualquiera puede desactivar la validación del navegador o enviar datos directamente a tu endpoint.
Botones
<!-- submit — envía el formulario -->
<button type="submit">Enviar</button>
<!-- reset — limpia todos los campos al valor inicial -->
<button type="reset">Limpiar</button>
<!-- button — sin comportamiento por defecto (para JS) -->
<button type="button" onclick="calcular()">Calcular</button>
<!-- input type submit —equivalente pero sin HTML dentro -->
<input type="submit" value="Enviar">
<button> acepta HTML adentro — podés poner iconos, spans con estilos, etc. <input type="submit"> solo admite texto plano.
fieldset y legend — agrupar campos
<fieldset> agrupa campos relacionados y <legend> le da un título al grupo. Mejora la organización visual y la accesibilidad.
<form action="/registro" method="POST">
<fieldset>
<legend>Datos personales</legend>
<label for="nombre">Nombre:</label>
<input type="text" id="nombre" name="nombre" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</fieldset>
<fieldset>
<legend>Contraseña</legend>
<label for="pass">Contraseña:</label>
<input type="password" id="pass" name="pass" minlength="8" required>
<label for="pass2">Repetir contraseña:</label>
<input type="password" id="pass2" name="pass2" required>
</fieldset>
<button type="submit">Registrarse</button>
</form>
Probá el Ejemplo 4: Formulario de registro completo
Buenas Prácticas
- Siempre alt en las imágenes: vacío
alt=""si son decorativas, descriptivo si aportan contenido - Definí width y height en imágenes: el navegador reserva el espacio antes de cargar y evita el salto de layout (CLS)
- Tablas solo para datos tabulares: nunca para maquetar columnas o layouts — para eso usá CSS Flexbox o Grid
- Siempre usá label con for/id: es clave para usabilidad y lectores de pantalla
- name en cada campo: sin
nameel campo no se envía en el formulario - Validación HTML como primera capa: completala siempre con validación del lado del servidor
- method="POST" para datos sensibles: contraseñas, información personal, pagos — nunca GET