Saltar al contenido
schedule 15 min HTML

Formularios

Los formularios son la única forma que tiene un usuario de enviar datos a una web: registrarse, iniciar sesión, buscar, comprar, comentar, contactar... Sin formularios, la web sería solo lectura. Esta es una de las lecciones más importantes del curso.

La etiqueta <form>

Todo formulario empieza con <form>. Esta etiqueta agrupa todos los campos y define a dónde se envían los datos:

contacto.html
<form action="/enviar-contacto" method="POST">
    <!-- Campos del formulario van aquí -->
</form>
  • action: la URL del servidor que procesará los datos.
  • method: cómo se envían. GET pone los datos en la URL (búsquedas), POST los envía en el cuerpo de la petición (datos sensibles, formularios largos).

Inputs: los campos del formulario

La etiqueta <input> es la más versátil. Su atributo type define qué tipo de campo muestra:

registro.html
<form action="/registro" method="POST">
    <label for="nombre">Nombre completo</label>
    <input type="text" id="nombre" name="nombre" required>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" required>

    <label for="password">Contraseña</label>
    <input type="password" id="password" name="password"
           minlength="8" required>

    <label for="nacimiento">Fecha de nacimiento</label>
    <input type="date" id="nacimiento" name="nacimiento">

    <button type="submit">Crear cuenta</button>
</form>

Tipos de input que debes conocer

Tipo Qué muestra Ejemplo de uso
text Campo de texto libre Nombre, ciudad, empresa
email Campo que valida formato de email [email protected]
password Oculta los caracteres Contraseña, PIN
number Solo números, con flechas ↑↓ Edad, cantidad, precio
tel Teclado numérico en móvil Teléfono
url Valida formato de URL Sitio web, portfolio
date Selector de fecha nativo Fecha de nacimiento, reserva
time Selector de hora Hora de la cita
color Selector de color Color favorito, tema
range Slider (barra deslizante) Volumen, brillo, precio máx.
file Selector de archivos Subir avatar, documentos
search Campo de búsqueda (con X para limpiar) Buscador del sitio
checkbox Casilla de verificación Aceptar términos, preferencias
radio Opción única entre varias Plan, género, método de pago
hidden Campo invisible (datos internos) ID del producto, token CSRF

Usar el type correcto no es solo estético. En móvil, type="email" muestra un teclado con @, type="tel" muestra un teclado numérico. Los usuarios te lo agradecen.

Labels: accesibilidad obligatoria

Cada campo necesita un <label>. Sin label, los usuarios con lectores de pantalla no saben qué dato pide cada campo:

<!-- Método 1: label con for + input con id (recomendado) -->
<label for="ciudad">Ciudad</label>
<input type="text" id="ciudad" name="ciudad">

<!-- Método 2: input dentro del label (también válido) -->
<label>
    Ciudad
    <input type="text" name="ciudad">
</label>

El atributo for del label debe coincidir con el id del input. Esto tiene un bonus: al hacer clic en el label, el navegador enfoca el input. En checkboxes y radios esto es especialmente útil porque amplía la zona clicable.

Textarea, select y datalist

feedback.html
<form action="/feedback" method="POST">
    <!-- Área de texto para textos largos -->
    <label for="comentario">Tu opinión</label>
    <textarea id="comentario" name="comentario" rows="5"
              placeholder="Cuéntanos qué podemos mejorar..."></textarea>

    <!-- Select para elegir una opción de una lista -->
    <label for="categoria">Categoría</label>
    <select id="categoria" name="categoria">
        <option value="">Selecciona una categoría</option>
        <option value="bug">Bug o error</option>
        <option value="feature">Sugerencia de funcionalidad</option>
        <option value="ui">Diseño / interfaz</option>
        <option value="rendimiento">Rendimiento</option>
    </select>

    <!-- Datalist: input con sugerencias (autocomplete libre) -->
    <label for="navegador">Navegador</label>
    <input type="text" id="navegador" name="navegador" list="navegadores">
    <datalist id="navegadores">
        <option value="Chrome">
        <option value="Firefox">
        <option value="Safari">
        <option value="Edge">
        <option value="Arc">
        <option value="Brave">
    </datalist>

    <button type="submit">Enviar feedback</button>
</form>

La diferencia entre <select> y <datalist>: con select estás limitado a las opciones que hay. Con datalist puedes escribir lo que quieras además de elegir las sugerencias.

Validación nativa de HTML

No necesitas JavaScript para validar formularios básicos. HTML tiene validación incorporada:

pedido.html
<form action="/pedido" method="POST">
    <!-- Campo obligatorio -->
    <label for="producto">Producto</label>
    <input type="text" id="producto" name="producto" required>

    <!-- Rango de valores -->
    <label for="cantidad">Cantidad (1-99)</label>
    <input type="number" id="cantidad" name="cantidad"
           min="1" max="99" value="1" required>

    <!-- Patrón regex -->
    <label for="codigo">Código postal (5 dígitos)</label>
    <input type="text" id="codigo" name="codigo"
           pattern="[0-9]{5}"
           title="Introduce un código postal de 5 dígitos"
           required>

    <!-- Longitud mínima y máxima -->
    <label for="usuario">Nombre de usuario (3-20 caracteres)</label>
    <input type="text" id="usuario" name="usuario"
           minlength="3" maxlength="20" required>

    <button type="submit">Hacer pedido</button>
</form>
Atributo Qué valida
required El campo no puede estar vacío
min / max Valor mínimo/máximo (números, fechas)
minlength / maxlength Longitud mínima/máxima del texto
pattern Expresión regular personalizada
type="email" Formato de email válido
type="url" Formato de URL válido

Los pseudo-selectores CSS :user-valid y :user-invalid permiten estilizar los campos según su estado de validación, pero solo después de que el usuario interactúe con ellos. Esto evita que el formulario aparezca "lleno de errores" antes de escribir nada. Los verás en la sección de CSS.

Checkboxes y radio buttons

preferencias.html
<form action="/preferencias" method="POST">
    <!-- Checkboxes: múltiples opciones -->
    <fieldset>
        <legend>Géneros de videojuegos que te gustan</legend>
        <label><input type="checkbox" name="generos[]" value="rpg"> RPG</label>
        <label><input type="checkbox" name="generos[]" value="fps"> FPS</label>
        <label><input type="checkbox" name="generos[]" value="estrategia"> Estrategia</label>
        <label><input type="checkbox" name="generos[]" value="plataformas"> Plataformas</label>
        <label><input type="checkbox" name="generos[]" value="sandbox"> Sandbox</label>
    </fieldset>

    <!-- Radio buttons: solo una opción -->
    <fieldset>
        <legend>Plataforma principal</legend>
        <label><input type="radio" name="plataforma" value="pc" checked> PC</label>
        <label><input type="radio" name="plataforma" value="ps5"> PlayStation 5</label>
        <label><input type="radio" name="plataforma" value="xbox"> Xbox Series X</label>
        <label><input type="radio" name="plataforma" value="switch"> Nintendo Switch 2</label>
    </fieldset>

    <button type="submit">Guardar preferencias</button>
</form>

<fieldset> agrupa campos relacionados y <legend> le da un título al grupo. Esto es clave para accesibilidad: los lectores de pantalla anuncian "Géneros de videojuegos que te gustan" antes de cada checkbox del grupo.

Los radio buttons con el mismo name forman un grupo exclusivo: solo puedes seleccionar uno.

Ejemplo completo: formulario de reserva

reserva.html
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Reservar mesa — Restaurante Umami</title>
</head>
<body>
    <h1>Reserva tu mesa en Umami</h1>
    <p>Cocina fusión japonesa-mediterránea en el centro de Madrid.</p>

    <form action="/reservar" method="POST">
        <label for="nombre">Nombre de la reserva</label>
        <input type="text" id="nombre" name="nombre" required
               autocomplete="name">

        <label for="email">Email de confirmación</label>
        <input type="email" id="email" name="email" required
               autocomplete="email">

        <label for="telefono">Teléfono</label>
        <input type="tel" id="telefono" name="telefono" required
               autocomplete="tel">

        <label for="fecha">Fecha</label>
        <input type="date" id="fecha" name="fecha" required
               min="2026-03-15">

        <label for="hora">Hora</label>
        <input type="time" id="hora" name="hora" required
               min="13:00" max="23:00" step="1800">

        <label for="comensales">Número de comensales</label>
        <input type="number" id="comensales" name="comensales"
               min="1" max="12" value="2" required>

        <fieldset>
            <legend>Zona preferida</legend>
            <label><input type="radio" name="zona" value="interior" checked> Interior</label>
            <label><input type="radio" name="zona" value="terraza"> Terraza</label>
            <label><input type="radio" name="zona" value="barra"> Barra</label>
        </fieldset>

        <label for="notas">Notas especiales</label>
        <textarea id="notas" name="notas" rows="3"
                  placeholder="Alergias, celebraciones, silla para bebé..."></textarea>

        <label>
            <input type="checkbox" name="terminos" required>
            Acepto la política de cancelación
        </label>

        <button type="submit">Confirmar reserva</button>
    </form>
</body>
</html>

Fíjate en el atributo autocomplete. Le dice al navegador qué tipo de dato es para que pueda autocompletar con los datos guardados del usuario. Mejora mucho la experiencia en móvil.

code

Crea un formulario de registro para una plataforma

Medio schedule 15 min

Crea un archivo registro.html con un formulario de registro para una plataforma inventada (una app de recetas, un marketplace de segunda mano, una red social de mascotas...). Debe incluir:

  • Campos de texto: nombre, email, contraseña
  • Un <select> para elegir el país
  • Checkboxes para intereses o preferencias
  • Radio buttons para elegir un plan (free/premium)
  • Un <textarea> para "Cuéntanos sobre ti"
  • Validación nativa: required, minlength, pattern donde tenga sentido
  • Todos los campos con <label>
  • Al menos un <fieldset> con <legend>
lightbulb Pistas

Usa autocomplete en los campos de nombre, email y teléfono. Para la contraseña, usa minlength="8" y autocomplete="new-password". El checkbox de "Acepto los términos" debe ser required.

Newsletter

Recibe nuevos cursos, actualizaciones, artículos del blog y promociones en tu correo.