Acerca de este problema HTML
El rol ARIA button indica a los navegadores y tecnologías de asistencia que un elemento se comporta como un botón. Según la especificación WAI-ARIA, los elementos con role="button" siguen las mismas restricciones de contenido que los elementos <button> nativos. Específicamente, no deben contener contenido interactivo como descendientes. El elemento <input> se considera contenido interactivo, por lo que anidarlo dentro de cualquier elemento con role="button" es inválido.
Esta restricción existe por importantes razones de accesibilidad y usabilidad. Cuando un lector de pantalla encuentra un elemento con role="button", lo anuncia como un único control accionable. Si ese botón contiene otro elemento interactivo como un <input>, el usuario se enfrenta a interacciones conflictivas — ¿debería activar el elemento para desencadenar la acción del botón o interactuar con el input? Esta ambigüedad confunde tanto a las tecnologías de asistencia como a los usuarios. Los navegadores también pueden manejar eventos de foco y clic de manera impredecible cuando los elementos interactivos están anidados de esta forma.
La misma regla se aplica a elementos <button> nativos, elementos <a> con un href, y cualquier otro elemento que ya sea interactivo. Agregar role="button" a un <div> o <span> lo eleva al mismo estatus, por lo que se aplican las mismas restricciones de anidamiento.
Para solucionar este problema, considera estos enfoques:
-
Mueve el
<input>fuera del elemento con rol de botón y posiciónelos como elementos hermanos. -
Reemplaza el
<input>con contenido no interactivo como un<span>estilizado para verse como el control deseado, con atributos ARIA apropiados para transmitir el estado. - Repiensa la estructura del componente — si necesitas tanto una acción de botón como un input, deberían ser controles separados que estén agrupados visualmente pero no anidados.
Ejemplos
❌ Inválido: <input> anidado dentro de un elemento con role="button"
<div role="button" tabindex="0">
<input type="checkbox" />
Accept terms
</div>
❌ Inválido: <input> anidado dentro de un <button> nativo
<button>
<input type="text" />
Search
</button>
✅ Válido: Separa el <input> y el botón en elementos hermanos
<label>
<input type="checkbox" />
Accept terms
</label>
<button>Submit</button>
✅ Válido: Usa contenido no interactivo dentro del elemento con rol de botón
Si quieres un botón estilo toggle que transmita estado marcado/no marcado, usa atributos ARIA en el botón mismo en lugar de incrustar un <input>:
<div role="button" tabindex="0" aria-pressed="false">
<span aria-hidden="true">☐</span>
Accept terms
</div>
✅ Válido: Usa un <label> e <input> junto con un botón
<div>
<label>
<input type="checkbox" />
Accept terms
</label>
<div role="button" tabindex="0">Continue</div>
</div>
✅ Válido: Botón con solo contenido de frases no interactivo
<div role="button" tabindex="0">
<span>Click me</span>
</div>
Cuando tengas dudas, mantén los elementos interactivos como controles separados y distintos en lugar de anidarlos. Esto asegura semántica clara, comportamiento predecible entre navegadores, y una buena experiencia para usuarios de tecnologías de asistencia.
Encuentra problemas como este automáticamente
Rocket Validator escanea miles de páginas en segundos, detectando problemas de HTML en todo tu sitio web.