<fieldset>, <legend>
Formularios
Agrupa controles de formulario relacionados bajo un tema común. <legend> es el título del grupo y debe ser el primer hijo del fieldset. Los lectores de pantalla anuncian el legend cuando el foco entra a cualquier control del grupo, dando contexto sin que el usuario tenga que explorar.
<fieldset> agrupa controles de formulario que pertenecen al mismo tema o paso. Cuando un formulario tiene secciones — datos personales, dirección de envío, método de pago — <fieldset> comunica esa estructura tanto visualmente (el borde y el título del grupo) como semánticamente (un grupo de controles en el árbol de accesibilidad). Sin él, una serie de campos son solo una lista plana de controles sin relación explícita entre ellos.
<legend> es el elemento que da nombre al grupo y debe ser el primer hijo directo del <fieldset>. Su posición no es negociable según la spec: el navegador lo coloca visualmente sobre el borde superior del fieldset, y los lectores de pantalla lo usan como nombre del grupo. El texto del <legend> es lo que el lector de pantalla anuncia cuando el foco llega a cualquier control dentro del fieldset — el usuario escucha “Datos de contacto: Nombre — campo de texto” en lugar de solo “Nombre — campo de texto”, con lo que entiende el contexto de la sección sin necesidad de navegar por toda la página.
Hay un uso específico donde <fieldset> es prácticamente obligatorio desde el punto de vista de la accesibilidad: los grupos de radio buttons. Individualmente, un radio button tiene su propio <label> que dice “Tarjeta de crédito” o “Tarjeta de débito”. Pero ¿crédito o débito de qué? Sin el <fieldset> con <legend> que diga “Método de pago”, el usuario de lector de pantalla no tiene contexto. El fieldset es el que completa la pregunta.
Cómo funciona
<fieldset> genera un “grupo de formulario” (role="group") en el árbol de accesibilidad. El texto del <legend> se convierte en el nombre de ese grupo. Cuando el foco entra a cualquier control dentro del fieldset, el lector de pantalla anuncia el nombre del grupo antes del nombre del campo: “Datos de contacto: Nombre — campo de texto”. Sin fieldset, el contexto se pierde.
El borde visual es el estilo por defecto del navegador. En producción, generalmente se resetea con CSS y se diseña el agrupamiento visualmente de otra manera, pero la estructura semántica se mantiene.
Modelo de contenido
<fieldset> acepta contenido de flujo, con la restricción de que el primer hijo debe ser un <legend>. El <legend> acepta contenido en línea (texto, <strong>, <span>, <em>).
Display por defecto de <fieldset>: block. Display de <legend>: depende del navegador, pero visualmente flota sobre el borde del fieldset.
Sintaxis
<!-- Patrón básico: siempre legend como primer hijo -->
<fieldset>
<legend>Datos personales</legend>
<label for="nombre">Nombre</label>
<input type="text" id="nombre" name="nombre">
<label for="correo">Correo electrónico</label>
<input type="email" id="correo" name="correo">
</fieldset>
<!-- Caso de uso clásico: grupo de radio buttons -->
<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>
<input type="radio" id="transferencia" name="pago" value="transferencia">
<label for="transferencia">Transferencia bancaria</label>
</fieldset>
Atributos de <fieldset>
disabled — deshabilitar todo el grupo
Atributo booleano. Cuando está presente en el <fieldset>, todos los controles dentro del fieldset quedan deshabilitados como si cada uno tuviera disabled individualmente. Sus valores no se envían al servidor.
<!-- Todos los controles dentro quedan deshabilitados -->
<fieldset disabled>
<legend>Dirección de envío (completá tus datos primero)</legend>
<input type="text" name="calle">
<input type="text" name="ciudad">
</fieldset>
Cuándo usarlo: formularios multipaso donde la sección siguiente no está disponible hasta completar la anterior. O para mostrar datos de lectura sin necesidad de deshabilitar cada control individualmente.
Importante: el <legend> no se deshabilita con el fieldset — sigue visible y accesible.
name — nombre del fieldset
Rara vez necesario. El name del fieldset no se usa en el envío de datos — son los controles individuales los que tienen name. Se usa en JavaScript para acceder al fieldset como elemento del DOM.
form — asociar a un formulario externo
Igual que en <button> e <input>, permite que el fieldset y sus controles estén asociados a un <form> con ese id aunque estén fuera de él en el DOM.
<legend> — título del grupo
El <legend> debe ser el primer hijo del <fieldset>. Su texto es el nombre del grupo en el árbol de accesibilidad. Acepta contenido en línea: texto, <strong>, <abbr>, <span>.
<fieldset>
<legend>Datos de <strong>facturación</strong></legend>
…
</fieldset>
Gotcha: mover el <legend> con CSS (para cambiar su posición visual) puede causar comportamiento inconsistente entre navegadores. Si el diseño requiere el título en otro lugar, es mejor resetear el estilo del fieldset y usar un <div> o <h2> para el encabezado visual, con aria-labelledby en el fieldset para mantener la accesibilidad.
Accesibilidad
El rol implícito de <fieldset> es group. El rol de <legend> es group label. Esta combinación es el patrón correcto para grupos de controles relacionados.
Por qué es crítico para radio buttons: los radio buttons sin <fieldset>/<legend> no tienen contexto de grupo. El lector de pantalla anuncia “Tarjeta de crédito — radio button” sin saber a qué pregunta corresponde. Con el fieldset, anuncia “Método de pago: Tarjeta de crédito — radio button”. El cambio de comprensión para el usuario es enorme.
<!-- ❌ Radio buttons sin contexto de grupo -->
<input type="radio" name="pago" id="cred" value="credito">
<label for="cred">Tarjeta de crédito</label>
<input type="radio" name="pago" id="deb" value="debito">
<label for="deb">Tarjeta de débito</label>
<!-- ✅ Con fieldset/legend: el grupo tiene nombre -->
<fieldset>
<legend>Método de pago</legend>
<input type="radio" name="pago" id="cred" value="credito">
<label for="cred">Tarjeta de crédito</label>
<input type="radio" name="pago" id="deb" value="debito">
<label for="deb">Tarjeta de débito</label>
</fieldset>
Cuándo usar <fieldset>
| Situación | ¿Fieldset? |
|---|---|
| Grupo de radio buttons | Siempre (obligatorio para accesibilidad) |
| Grupo de checkboxes relacionados | Siempre |
| Sección de un formulario largo (datos personales, dirección, pago) | Recomendado |
| Formulario simple de 2-3 campos | Opcional |
| Un solo campo | No aplica |
Notas, gotchas e interacción
<legend>debe ser el primer hijo. Ponerlo después de otros elementos o no incluirlo rompe la semántica del fieldset. El<legend>se puede estilizar con CSS (tamaño, color, peso) para que no se vea como el estilo por defecto.fieldset disableddeshabilita todos los controles hijos. Esto incluye botones. Si hay un botón de “Siguiente” dentro del fieldset, también quedará deshabilitado. Pensá bien la estructura si usás esta feature.- El borde del fieldset es CSS, no semántica. Podés eliminarlo con
border: none; padding: 0; margin: 0sin perder la semántica. La agrupación semántica vive en los roles del árbol de accesibilidad, no en el borde visual. - Anidar fieldsets. Es válido anidar fieldsets (un formulario grande con secciones que tienen subsecciones). Los lectores de pantalla anuncian el legend del fieldset más cercano al control.
Vigente / legacy
<fieldset> y <legend> están completamente vigentes. No hay atributos legacy relevantes. El patrón de usar <fieldset> para agrupar radio buttons es práctica estándar recomendada por WCAG (Web Content Accessibility Guidelines).