Etiqueta menuitem en HTML: obsoleta y acciones actuales
La etiqueta <menuitem> está obsoleta y no debe usarse en HTML nuevo. Definía un comando que podía invocarse desde un menú emergente, incluida la propuesta de menús contextuales. Hoy utiliza controles nativos, como <button>, y programa la acción que corresponda. Esta guía explica su uso histórico y cómo migrarlo; el HTML Living Standard la incluye entre las funciones no conformes.
Sintaxis y contexto históricos
Este ejemplo antiguo sirve para reconocer la etiqueta. Se conserva como código de referencia y no debe ejecutarse como una demostración actual:
<menu type="context" id="acciones">
<menuitem label="Guardar" type="command">
</menu>
Pretendía declarar el comando «Guardar» de un menú contextual. En HTML 5.1 de noviembre de 2016, <menuitem> era vacío: no tenía hijos ni etiqueta de cierre. Su padre debía ser un <menu> en estado de menú emergente. El texto se expresaba mediante label.
El bloque conserva la variante type="context" para reconocer código heredado; no coincide con el valor type="popup" definido en esa edición de HTML 5.1. Ninguno de esos valores de <menu> es válido en la autoría actual.
El fragmento no incluía una acción de guardado. La antigua asociación con el objeto de la página usaba contextmenu="acciones"; esa declaración también está obsoleta. Su interoperabilidad dependía de la implementación: no funcionaba en todos los navegadores.
Menuitem frente a menu y al rol ARIA
<menu> sigue vigente: representa una lista de comandos, normalmente mediante hijos <li> que contienen controles. Admite contenido de flujo como contexto; no coloques una lista dentro de <p>. Sus hijos son <li> y elementos de apoyo a scripts, no botones directamente. Consulta su modelo de contenido actual.
role="menuitem" pertenece a WAI-ARIA. Es un rol para una opción de un widget de menú, no una etiqueta HTML ni un reemplazo que se añade a cualquier botón. Necesita el contexto accesible de un menu o menubar y la interacción correspondiente. Declarar el rol comunica semántica; no programa el teclado.
Una lista de botones nativos permite llegar a cada acción con Tab y activarla con Enter o Espacio. <menu> por sí solo no crea un menú desplegable ni navegación automática con flechas. Para dos acciones visibles, esta solución evita implementar un widget compuesto.
Atributos antiguos y sus reemplazos
Estos atributos específicos se documentan para interpretar código heredado, según la sección histórica de HTML 5.1 enlazada arriba:
| Atributo antiguo | Función histórica | Decisión actual |
|---|---|---|
label | Nombre; si aparecía, no podía estar vacío. | Texto visible dentro del botón. |
type | command por defecto, checkbox o radio. | Botón para acciones; casilla o radio para selección. |
icon | URL válida y no vacía de una imagen. | Imagen o SVG dentro del control; conserva un nombre textual. |
disabled | Booleano: comando no disponible. | disabled en un control nativo que lo admita. |
checked | Booleano; solo para checkbox o radio. | Estado del control de selección adecuado. |
radiogroup | Nombre no vacío; solo para radios hermanos. | Radios nativos con el mismo name. |
default | Booleano: comando predeterminado. | Diseña explícitamente la acción principal. |
disabled="false" conserva el atributo booleano y deshabilita un botón. Para habilitarlo, retira el atributo o asigna false a la propiedad DOM disabled, como en el ejemplo siguiente. En controles actuales de selección, el atributo checked fija el estado inicial; la propiedad DOM checked refleja el estado actual. Un botón de alternancia puede usar aria-pressed; no admite checked.
id, class, lang y title son atributos globales. El antiguo title ofrecía una pista, sin sustituir al nombre. display y gap son propiedades CSS; addEventListener() es un método de JavaScript para registrar manejadores. Copiar los atributos antiguos a un botón no reproduce su comportamiento.
Migración a dos acciones accesibles
Guarda este documento completo como acciones-notas.html en UTF-8 y ábrelo en el navegador. No requiere un servidor ni archivos adicionales. «Duplicar nota» añade una copia visible; «Restablecer» vuelve a una sola nota. Ambas acciones modifican únicamente esta página: no guardan archivos, no envían datos y se pierden 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 las notas</title>
<style>
body {
max-width: 36rem;
margin-inline: auto;
padding: 1rem;
font-family: sans-serif;
line-height: 1.5;
}
#menuitem-ejemplo menu {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
padding: 0;
list-style: none;
}
#menuitem-ejemplo button {
padding: 0.6rem 0.8rem;
font: inherit;
}
</style>
</head>
<body>
<section id="menuitem-ejemplo">
<h1>Acciones de las notas</h1>
<ul data-notas>
<li>Revisar el borrador.</li>
</ul>
<menu aria-label="Acciones de las notas">
<li><button type="button" data-duplicar disabled>Duplicar nota</button></li>
<li><button type="button" data-restablecer disabled>Restablecer</button></li>
</menu>
<p role="status" data-estado>Una nota disponible.</p>
<noscript>
<p>Las acciones necesitan JavaScript. Puedes leer la nota y copiar su texto manualmente.</p>
</noscript>
</section>
<script>
(() => {
const ejemplo = document.getElementById("menuitem-ejemplo");
const notas = ejemplo.querySelector("[data-notas]");
const estado = ejemplo.querySelector("[data-estado]");
const duplicar = ejemplo.querySelector("[data-duplicar]");
const restablecer = ejemplo.querySelector("[data-restablecer]");
const textoInicial = notas.firstElementChild.textContent;
function crearNota() {
const nota = document.createElement("li");
nota.textContent = textoInicial;
return nota;
}
duplicar.addEventListener("click", () => {
notas.append(crearNota());
estado.textContent = `Se añadió una copia. Hay ${notas.children.length} notas.`;
});
restablecer.addEventListener("click", () => {
notas.replaceChildren(crearNota());
estado.textContent = "Lista restablecida. Una nota disponible.";
});
duplicar.disabled = false;
restablecer.disabled = false;
})();
</script>
</body>
</html>
Prueba Tab hasta «Duplicar nota» y pulsa Enter: aparecerán dos notas y un mensaje. Pulsa Espacio para añadir otra; después, Tab y Enter en «Restablecer» recuperan la lista inicial. El foco permanece en el botón activado. role="status" expone la actualización a tecnologías de asistencia; el anuncio concreto depende de su combinación con el navegador.
Sin JavaScript, los botones permanecen deshabilitados y aparece la explicación de la alternativa manual. La nota sigue disponible. Retirar CSS cambia la disposición, sin eliminar controles ni contenido. Al migrar, cambia también los selectores que buscaban menuitem: renombrar la etiqueta o retirarla sin crear los controles y sus manejadores pierde la acción.
Menús contextuales y errores frecuentes
Un menú contextual personalizado exige más trabajo. Antes de interceptar contextmenu, proporciona una apertura por teclado, por ejemplo un botón visible, y aplica el patrón de menú de WAI-ARIA APG: mueve el foco al abrir, recorre las opciones con flechas, activa con Enter y cierra con Escape devolviendo el foco al origen. Tab debe salir del widget; los submenús requieren su propia gestión. Los estados de selección usan menuitemcheckbox o menuitemradio y aria-checked cuando corresponda.
No bloquees el menú del navegador sin una razón y una alternativa accesible. El ejemplo anterior mantiene sus acciones visibles y no intercepta ese evento. Evita asimismo añadir role="menu" a una lista que solo funciona con Tab, convertir texto en un supuesto botón con CSS o depender de un icono sin nombre comprensible.
Preguntas frecuentes y guías relacionadas
¿Menu también está obsoleta?
No. Sigue vigente como lista de comandos. Lo obsoleto es <menuitem> y el antiguo modelo declarativo de menús contextuales, incluidos type="context" y el atributo contextmenu.
¿Role menuitem es la misma etiqueta?
No. role="menuitem" expresa semántica ARIA para un widget con requisitos de foco y teclado. No convierte una etiqueta obsoleta en HTML conforme ni aporta interacción automáticamente.
Para ampliar la migración, consulta las guías de <menu>, que agrupa comandos; <li>, que estructura cada entrada; y <button>, que ofrece la activación nativa. <script> contiene aquí la lógica local; HTML por sí solo no duplica ni restablece la nota.
Compatibilidad y fuentes
Referencia revisada el 5 de octubre de 2026. Las notas oficiales de Firefox 85, publicado el 26 de enero de 2021, documentan que <menuitem> dejó de estar disponible por defecto y quedó detrás de una preferencia. Es evidencia de una implementación histórica, no soporte actual interoperable.
Contrasta el código heredado con HTML 5.1 y la autoría vigente con el Living Standard. Para widgets compuestos, consulta WAI-ARIA y su patrón APG, enlazados en las secciones anteriores. Que un navegador conserve algún comportamiento antiguo no elimina la obsolescencia.