Acerca de este problema HTML
El elemento <button> tiene un modelo de contenido estricto definido por el WHATWG HTML Living Standard: acepta contenido de frases, pero con la exclusión explícita del contenido interactivo. El elemento <input> se clasifica como contenido interactivo, lo que significa que anidarlo dentro de un <button> produce HTML inválido y desencadena este error del validador W3C.
Por qué esto es un problema
Comportamiento impredecible del navegador: Cuando los elementos interactivos están anidados dentro de un <button>, los navegadores deben determinar qué elemento debe recibir las interacciones del usuario como clics, foco y entrada de teclado. Diferentes navegadores manejan esto de manera diferente — algunos pueden ignorar completamente el <input> interno, mientras que otros pueden producir un comportamiento confuso donde los clics son absorbidos por el <button> antes de llegar al <input>.
Problemas de accesibilidad: Los lectores de pantalla y otras tecnologías de asistencia esperan que un <button> contenga texto descriptivo o contenido de frases simple, no otros controles de formulario. Anidar un <input> dentro de un <button> crea una experiencia confusa y potencialmente inutilizable para usuarios que dependen de tecnología de asistencia. La relación entre los dos controles se vuelve ambigua — ¿está interactuando el usuario con el botón o con el input?
Cumplimiento de estándares: Un HTML válido es la base para un renderizado y comportamiento consistente a través de navegadores y dispositivos. Usar anidación inválida puede llevar a errores sutiles que son difíciles de diagnosticar, especialmente cuando los navegadores actualizan su comportamiento de análisis.
Otros elementos que no puedes anidar dentro de <button>
La restricción se aplica a todo el contenido interactivo, no solo a <input>. Tampoco puedes colocar estos elementos dentro de un <button>:
-
<a>(con un atributohref) -
<button> -
<select> -
<textarea> -
<label> -
<audio>y<video>(concontrols) -
<embed>,<iframe>,<object> -
Cualquier elemento con un atributo
tabindex
Cómo solucionarlo
La solución es sencilla: mueve el <input> fuera del <button> para que sean elementos hermanos. Envuélvelos en un <form>, <div>, u otro contenedor adecuado, y usa CSS para lograr cualquier diseño visual deseado.
Ejemplos
❌ Inválido: <input> anidado dentro de <button>
<button>
Submit
<input type="text" name="example">
</button>
Esto desencadena el error porque <input> es contenido interactivo colocado dentro de un <button>.
✅ Solucionado: <input> y <button> como hermanos
<form>
<input type="text" name="example">
<button type="submit">Submit</button>
</form>
Ambos elementos son hijos directos del <form>, haciendo que el marcado sea válido y los controles independientemente accesibles.
❌ Inválido: <input> oculto dentro de <button>
Podrías pensar que un input oculto está bien ya que no es visualmente interactivo, pero <input type="hidden"> sigue siendo un elemento <input> y sigue estando prohibido dentro de <button>:
<button type="submit">
Save
<input type="hidden" name="action" value="save">
</button>
✅ Solucionado: <input> oculto movido fuera de <button>
<form>
<input type="hidden" name="action" value="save">
<button type="submit">Save</button>
</form>
❌ Inválido: Checkbox dentro de un <button> para un efecto de alternancia
<button class="toggle">
<input type="checkbox" name="darkmode"> Dark Mode
</button>
✅ Solucionado: Usa un <label> en su lugar
Si la intención es una alternancia clicable, un <label> emparejado con un checkbox logra el mismo resultado visual con marcado válido y accesible:
<label class="toggle">
<input type="checkbox" name="darkmode"> Dark Mode
</label>
Alternativamente, si realmente necesitas un botón que alterne el estado, usa JavaScript con el atributo aria-pressed en lugar de embeber un checkbox:
<button type="button" class="toggle" aria-pressed="false">
Dark Mode
</button>
Mantén <input> y <button> como elementos separados y hermanos. Si necesitas que aparezcan visualmente agrupados, usa CSS para el diseño y estilo en lugar de anidar un elemento interactivo dentro de otro.
Encuentra problemas como este automáticamente
Rocket Validator escanea miles de páginas en segundos, detectando problemas de HTML en todo tu sitio web.