Etiqueta menu en HTML: listas de comandos y acciones
La etiqueta <menu> en HTML representa una lista de elementos que contienen comandos o acciones. Úsala para reunir los botones de una herramienta, como guardar y duplicar una nota o añadir y vaciar tareas. Describe el grupo de acciones; cada botón proporciona el control y la aplicación debe añadir la lógica de cada acción.
<menu>
<li><button type="button">Guardar</button></li>
<li><button type="button">Duplicar</button></li>
</menu>
Normalmente verás una lista con viñetas y dos botones. Puedes llegar a ellos con Tab y activarlos con Enter o Espacio, pero este fragmento todavía no guarda ni duplica nada: le faltan los handlers que ejecutan esas operaciones. type="button" pertenece al botón y evita que actúe como botón de envío si lo colocas en un formulario.
Sintaxis y contexto válido
Escribe <menu>…</menu> donde se permita contenido de flujo, por ejemplo dentro del cuerpo de la página o de una sección. No lo introduzcas dentro de un párrafo. Sus hijos directos pueden ser cero o más <li> y elementos de soporte de scripts, como <script> y <template>; los botones van dentro de los <li>.
Ambas etiquetas de <menu> se escriben explícitamente: ni la apertura ni el cierre se pueden omitir. El HTML Living Standard define este modelo de contenido. Un botón directamente bajo <menu> queda fuera de ese modelo, aunque el navegador lo muestre.
Menu frente a ul y nav
La elección depende de lo que reúnes:
<menu>expresa una lista de comandos, como «Añadir tarea» y «Vaciar lista».<ul>expresa una lista general cuyo orden no determina su significado, como las tareas pendientes. También puede contener botones, pero no comunica específicamente la intención de agrupar comandos.<nav>identifica una sección de navegación hacia otras páginas o partes de la página. Un menú principal con enlaces a «Inicio» y «Cursos» suele necesitar<nav>y puede organizar sus enlaces mediante<ul>.
La palabra «menú» en el diseño de una web no determina la etiqueta. Para enlaces de navegación, consulta la definición de <nav> en el estándar.
Menu no implementa un widget ARIA
La semántica accesible implícita de <menu> es list, según ARIA en HTML. Los botones interiores conservan su comportamiento normal: Tab recorre los controles y Shift + Tab retrocede. La etiqueta no incorpora desplazamiento del foco con flechas, submenús ni un menú del sistema.
No añadas role="menu" solo por el nombre del elemento. Ese rol describe un widget compuesto con otra gestión del foco y del teclado. Implementarlo exige las relaciones, estados e interacciones del patrón de menú de WAI-ARIA, incluidas las flechas y el cierre cuando corresponda. Para una barra sencilla de botones, conserva la interacción nativa.
Ejemplo práctico: una barra de acciones para tareas
Guarda este documento como acciones.html en UTF-8 y ábrelo en el navegador. Incluye HTML, CSS y JavaScript; no necesita servidor, archivos adicionales ni servicios externos. Los cambios existen solo en la página abierta y desaparecen al recargar.
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Acciones de la lista de tareas</title>
<style>
body {
max-width: 42rem;
margin-inline: auto;
padding: 1rem;
font-family: system-ui, sans-serif;
}
.menu-demo-acciones {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 2rem;
padding-inline-start: 1.5rem;
}
.menu-demo-acciones button {
font: inherit;
padding: 0.45rem 0.75rem;
}
.menu-demo-acciones button:focus-visible {
outline: 3px solid #164b92;
outline-offset: 3px;
}
</style>
</head>
<body>
<h1>Lista de tareas</h1>
<p>Con JavaScript puedes añadir una tarea de ejemplo o vaciar
la lista. Sin JavaScript puedes leerla; los botones quedan
deshabilitados. Los cambios no se guardan.</p>
<menu class="menu-demo-acciones">
<li>
<button id="menu-demo-anadir" type="button" disabled>
Añadir tarea
</button>
</li>
<li>
<button id="menu-demo-vaciar" type="button" disabled>
Vaciar lista
</button>
</li>
</menu>
<ul id="menu-demo-tareas">
<li>Revisar el correo</li>
</ul>
<p id="menu-demo-estado" role="status">
Las acciones requieren JavaScript; la lista se puede leer.
</p>
<script>
const tareas = document.getElementById('menu-demo-tareas');
const anadir = document.getElementById('menu-demo-anadir');
const vaciar = document.getElementById('menu-demo-vaciar');
const estado = document.getElementById('menu-demo-estado');
let siguiente = 1;
function actualizarEstado() {
const total = tareas.children.length;
estado.textContent = total === 1
? '1 tarea en la lista.'
: `${total} tareas en la lista.`;
}
anadir.addEventListener('click', () => {
const tarea = document.createElement('li');
tarea.textContent = `Tarea nueva ${siguiente}`;
siguiente += 1;
tareas.append(tarea);
actualizarEstado();
});
vaciar.addEventListener('click', () => {
tareas.replaceChildren();
actualizarEstado();
});
anadir.disabled = false;
vaciar.disabled = false;
actualizarEstado();
</script>
</body>
</html>
- Al abrirlo con JavaScript verás «Revisar el correo», dos botones habilitados y «1 tarea en la lista». El script está después del marcado que consulta.
- Pulsa Tab hasta «Añadir tarea» y Enter: aparecerá «Tarea nueva 1» y el contador indicará dos tareas. Espacio vuelve a activar el botón y añade «Tarea nueva 2».
- Pulsa Tab para llegar a «Vaciar lista» y actívalo: desaparecen todas las tareas y el mensaje pasa a «0 tareas en la lista». Puedes añadir otra después; el foco permanece en el botón utilizado.
- Deshabilita JavaScript y recarga. Permanecen la tarea inicial y la explicación, con los botones deshabilitados. Reduce el ancho de la ventana:
flex-wrappermite que las acciones pasen a otra línea.
<menu> agrupa los comandos; <ul> contiene los datos que modifican. Si cambias <menu> por <ul> conservando la clase, los botones y los handlers, las acciones seguirán funcionando y la presentación será equivalente, pero perderás la distinción semántica de comandos. Si retiras solo las etiquetas del contenedor, dejarás sus <li> sueltos. Retirar el grupo completo elimina también sus controles: el script ya no puede consultar esos botones.
Atributos y accesibilidad
<menu> no tiene atributos específicos vigentes. Admite globales, como class para seleccionar el grupo desde CSS e id para identificarlo. En el ejemplo, type y disabled son atributos de <button>, no de <menu>. disabled es booleano: su presencia deshabilita; disabled="false" también lo mantiene deshabilitado. En JavaScript, la propiedad DOM .disabled = false sí habilita el botón.
display, gap y flex-wrap son propiedades CSS, y addEventListener() es un método de JavaScript: ninguno es un atributo de <menu>. La presentación horizontal la crea el CSS, no la etiqueta.
Los textos de los botones identifican sus acciones y el foco visible indica qué control vas a activar. role="status" en el párrafo permite exponer las actualizaciones del contador sin mover el foco. El anuncio concreto depende del navegador y del lector de pantalla. No añadas tabindex a cada <li> ni roles redundantes a los botones.
Errores frecuentes y preguntas
¿Menu crea un menú desplegable? No. La lista de acciones se presenta en el documento; mostrarla, ocultarla o implementar un desplegable requiere un diseño adicional.
¿Menu está obsoleta como menuitem? No. <menu> es vigente. <menuitem> pertenece a las funciones obsoletas del estándar. Los antiguos mecanismos de menús contextuales y atributos como type="context" no forman parte del uso actual. Tampoco uses el atributo histórico compact para modificar la apariencia: utiliza CSS.
¿Por qué los botones no hacen nada? Revisa si solo copiaste el fragmento mínimo, si JavaScript está habilitado, si los IDs coinciden y si el script se ejecuta después de crear los controles. Comprueba la consola para detectar errores; usar <menu> no conecta automáticamente las acciones.
Para profundizar, la guía de <li> explica cada entrada y la guía de <button> desarrolla los controles y sus tipos. Elige <ul> para listas generales y <nav> para secciones de navegación; la guía de <menuitem> sirve únicamente como referencia histórica.
Compatibilidad y fuentes
Consulta realizada el 5 de octubre de 2026: MDN clasifica <menu> como ampliamente disponible. Esto se refiere al elemento actual; no implica soporte de los antiguos menús contextuales. Su apariencia habitual se parece a la de <ul> y los estilos de la aplicación determinan cómo se distribuyen los controles.
Para significado, contenido permitido y atributos, usa la sección normativa de <menu>; para la semántica accesible, ARIA en HTML. La referencia de MDN complementa la explicación y la compatibilidad.